Calculating widget coordinate in UnrealEngine


widget coordinate system

suppose you have a game window. it might look like the picture and focus onto the popup widget

in this condition, we can call the coordinate system as Window Space

  • Window Space
    • a space has an origin with left-top of window
    • we can use this coordinate system for getting certain position in window

even we can imagine the coordinate system Monitor Space

  • Monitor Space
    • a space has an origin with left-top of monitor
    • we can use this coordinate system for getting certain position in monitor

※ position values are approximate
※ these terms are not official. they are just used for explaining this post

FGeometry introduction

1
2
3
4
5
6
7
8
9
10
11
12
13
UnrealEngine/Engine/Source/Runtime/SlateCore/Public/Layout/Geometry.h

/**
* Represents the position, size, and absolute position of a Widget in Slate.
* The absolute location of a geometry is usually screen space or
* window space depending on where the geometry originated.
* Geometries are usually paired with a SWidget pointer in order
* to provide information about a specific widget (see FArrangedWidget).
* A Geometry's parent is generally thought to be the Geometry of the
* the corresponding parent widget.
*/
USTRUCT(BlueprintType)
struct SLATECORE_API FGeometry
  • in unreal engine, FGeometry can help getting those transforms mentioned above
  • the FGeometry
    • contains useful data for widget especially the transform
    • is updated whenever widget is painted or ticked
  • every variance to transform is accumulated in FGeometry
    • in short, each tick, every widget has latest information for calculating transform
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
UnrealEngine/Engine/Source/Runtime/SlateCore/Private/Widgets/SWidget.h

//UE_DEPRECATED(4.23, "GetCachedGeometry has been deprecated, use GetTickSpaceGeometry instead")
const FGeometry& GetCachedGeometry() const;

/**
* Gets the last geometry used to Tick the widget. This data may not exist yet if this call happens prior to
* the widget having been ticked/painted, or it may be out of date, or a frame behind.
*
* We recommend not to use this data unless there's no other way to solve your problem. Normally in Slate we
* try and handle these issues by making a dependent widget part of the hierarchy, as to avoid frame behind
* or what are referred to as hysteresis problems, both caused by depending on geometry from the previous frame
* being used to advise how to layout a dependent object the current frame.
*/
const FGeometry& GetTickSpaceGeometry() const;

/**
* Gets the last geometry used to Tick the widget. This data may not exist yet if this call happens prior to
* the widget having been ticked/painted, or it may be out of date, or a frame behind.
*/
const FGeometry& GetPaintSpaceGeometry() const;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
UnrealEngine/Engine/Source/Runtime/SlateCore/Private/Widgets/SWidget.cpp

const FGeometry& SWidget::GetCachedGeometry() const
{
return GetTickSpaceGeometry();
}

const FGeometry& SWidget::GetTickSpaceGeometry() const
{
return PersistentState.DesktopGeometry;
}

const FGeometry& SWidget::GetPaintSpaceGeometry() const
{
return PersistentState.AllottedGeometry;
}
  • we can get FGeometry object via SWidget::Get*Geometry() series
    • FYI, SWidget::GetCachedGeometry() has been deprecated from 4.23
  • for general purpose, you can use any getter
    • DesktopGeometry and AllottedGeometry are not that different
    • but unreal engine recommend you to use AllottedGeometry one

※ for more information, visit reference #1 + reference #2 + reference #3

FGeometry APIs

  • GetLocalSize()
1
2
3
4
UnrealEngine/Engine/Source/Runtime/SlateCore/Public/Layout/Geometry.h

/** @return the size of the geometry in local space. */
FORCEINLINE const FVector2D& GetLocalSize() const { return Size; }

returns a size in local space. this size is usually determined with value set in editor

  • GetAbsoluteSize()
1
2
3
4
5
6
7
8
9
UnrealEngine/Engine/Source/Runtime/SlateCore/Public/Layout/Geometry.h

/**
* Get the absolute size of the geometry in render space.
*/
FORCEINLINE FVector2D GetAbsoluteSize() const
{
return AccumulatedRenderTransform.TransformVector(GetLocalSize());
}

returns a size in outer space. this size is based on your screen, which is real size

  • LocalToViewport()
1
2
3
4
5
6
7
8
9
10
11
12
13
UnrealEngine/Engine/Source/Runtime/UMG/Public/Blueprint/SlateBlueprintLibrary.h

/**
* Translates local coordinate of the geometry provided into local viewport coordinates.
*
* @param PixelPosition The position in the game's viewport, usable for line traces and
* other uses where you need a coordinate in the space of viewport resolution units.
* @param ViewportPosition The position in the space of other widgets in the viewport. Like if you wanted
* to add another widget to the viewport at the same position in viewport space as this location, this is
* what you would use.
*/
UFUNCTION(BlueprintPure, Category="User Interface|Geometry", meta=( WorldContext="WorldContextObject" ))
static void LocalToViewport(UObject* WorldContextObject, const FGeometry& Geometry, FVector2D LocalCoordinate, FVector2D& PixelPosition, FVector2D& ViewportPosition);

returns positions in outer space and local space respectively with parameters, which are PixelPosition and ViewportPosition

  • LocalToAbsolute()
1
2
3
4
5
6
7
8
9
10
11
UnrealEngine/Engine/Source/Runtime/UMG/Public/Blueprint/SlateBlueprintLibrary.h

/**
* Translates local coordinates into absolute coordinates
*
* Absolute coordinates could be either desktop or window space depending on what space the root of the widget hierarchy is in.
*
* @return Absolute coordinates
*/
UFUNCTION(BlueprintPure, Category="User Interface|Geometry")
static FVector2D LocalToAbsolute(const FGeometry& Geometry, FVector2D LocalCoordinate);

returns a position in Monitor Space

how to use

those APIs can be used for calculating transform. let us find out how to use them





Child Position Size Parent
Red One (100, 50) (60, 30) Canvas Panel #1
Green One (0, 0) (60, 30) Canvas Panel #2
Blue One NaN (60, 30) Horizontal Box
White One NaN (60, 30) Horizontal Box

we gotta use this widget for example. the widget has children with multiple depth. each editor property of child is above



※ transform property can be divided into local and absolute due to DPI Scale
※ in this example(and also default value), we got DPI Scale = 2/3 which means that every property gets multiplied with 0.666666…

  • Window Space

    • widget
      • size
        • local = Widget->GetCachedGeometry()->GetLocalSize()
        • absolute = Widget->GetCachedGeometry()->GetAbsoluteSize()
          (60, 30) * 0.666666… ≒ (39.99996…, 19.99998…)
      • position
        • local = Widget->GetCachedGeometry()->LocalToViewport()->ViewportPosition
        • absolute = Widget->GetCachedGeometry()->LocalToViewport()->PixelPosition
          (100, 50) * 0.666666… ≒ (66.66666…, 33.33333…)
  • verification (with Adobe Photoshop)

    • widget
      • size
      • position
  • Monitor Space

    • window
      • size
        • local approximately 1920x1080
        • absolute (1920, 1080) * 0.666666… = (1280, 720)
      • position
        • local
          cannot calculate. also not meaningful, unless the `DPI Scale` is the same with system's one
        • absolute
    • widget
      • size
        the same with before
      • position
        • local
          cannot calculate. also not meaningful, unless the DPI Scale is the same with system’s one
        • absolute
  • verification (with Adobe Photoshop)

    • window
      • size
      • position
    • widget
      • size
        the same with before
      • position

Window Space summary

Property Widget
Size.Local (60, 30)
Size.Absolute (40, 20)
Position.Local (100, 50)
Position.Absolute (66, 33)

Monitor Space summary

Property Window Widget
Size.Local (1920, 1080) (60, 30)
Size.Absolute (1280, 720) (40, 20)
Position.Local NaN NaN
Position.Absoulte (640, 350) (640 + 66, 350 + 33) = (706, 383)

widget translation

suppose you have to translate a widget into certain position. how will you ?
first, we need to check whether the slot of widget has SetPosition API. if the slot does not, we cannot do widget translation
but we can do it, as the red image was in Canvas Panel

1
2
3
4
5
UnrealEngine/Engine/Source/Runtime/UMG/Public/Components/CanvasPanelSlot.h

/** Sets the position of the slot */
UFUNCTION(BlueprintCallable, Category="Layout|Canvas Slot")
void SetPosition(FVector2D InPosition);

1
2
3
4
5
6
7
8
9
10
11
12
UnrealEngine/Engine/Source/Runtime/UMG/Public/Components/CanvasPanelSlot.cpp

void UCanvasPanelSlot::SetPosition(FVector2D InPosition)
{
LayoutData.Offsets.Left = InPosition.X;
LayoutData.Offsets.Top = InPosition.Y;

if ( Slot )
{
Slot->Offset(LayoutData.Offsets);
}
}

the parameter InPosition should be local position. it is easy to think, this is the same work with changing value in editor
second, we need to get local position of the widget. let us use the example red image again
in previous example, red image had a local position of (100, 50) in Window Space



let us move the widget with offset (100, 50) again
third, we need to set local position with new one. in this time, SetPosition(200, 100) will be needed
and we gotta check a local position at next tick. the local position would be (200, 100) and absolute position also be twice



  • verification (with Adobe Photoshop)
    • size
      the same with before
    • position
      • absolute position in Window Space
      • absolute position in Monitor Space

wrap-up !

  • getting local or absolute position is usually possible regardless of layout of widget such as widget hierarchy
  • we can only set local position through the API of slot such as Canvas Panel Slot
  • you need to calculate new position (based on several conditions, especially DPI Scale) to translate widget into desired position

Homepage

Career

Period Thing
2020.03 ~ now PUBG Studio, Live Tech Team at KRAFTON Inc.
2019.07 ~ 2021.06 PUBG Studio, Console Platform Contents Engineering Team at KRAFTON Inc.
2014.03 ~ 2020.02 Major CSE in Koreatech university
2018.11 ~ 2019.04 N2 unity client programmer
2015.05 ~ 2017.02 Service as Signal Corps in Republic of Korean Army

Contacts

Media URL
Github https://github.com/BaeMinCheon
Facebook https://www.facebook.com/Thanyang/
Email baemincheon@gmail.com
Twitter https://twitter.com/Ross_Public_

Practical usage of BlueprintImplementableEvent in UnrealEngine


two-edged Hot Reload

  • almost everyone uses this fascinating feature, which accelerates one’s development process
  • this feature can make you skip Editor loading, but cannot make you skip CPP compilation
    • in game development using Unreal Engine, most of time is still consumed in CPP compilation
  • even you may miss some of changes or encounter unexpected bugs
    • this means, Hot Reload feature is not the stable one

※ for more information, see the reference #1
※ one of the bugs: https://forums.unrealengine.com/unreal-engine/feedback-for-epic/37624-hot-reload-for-components-is-a-mess-with-the-hotreload-name-bug-at-the-moment

  • then, is there another way to reduce compilation time ?
    • while ensuring not to occur a malfunction ?
  • now it is time to use blueprint more practically

blueprint versus CPP

  • as we know, blueprint is useful enough to work with personal project
    • because there are no merge conflict and no number of context switchings in personal project
  • blueprint usually bullies developers in group project
    • because blueprint asset file is binary, there is no good way to merge them or see them without Editor
  • but blueprint instead has positive aspects in other sides
    • let us summary the pros and cons of blueprint
Item Blueprint CPP
Compilation absolutely fast (do not need to compile CPP) hell it is so slow (if with Engine build, too ? better kill me)
View & Diff must open Unreal Editor (even some changes cannot be shown) can be opened or diffed with common VCS such as git
Merge almost impossible (even need to re-work for rebase) not that different from merging an ordinary text file
Exception Handling warning in best and shutting down Game in worst unless handling, everyting shuts down (Editor, Game…etc)
Debugging can visit all nodes and variables some of codes can be optimized

※ for more information about Compilation item, see the reference #2

  • so, as you saw the table, I want to say that “prototyping with blueprint is quite useful”
  • in this post, I will show you one of tips to use blueprint efficiently
    • it may be faster than development using Hot Reload

BlueprintImplementableEvent

  • blueprint is efficient when it used only for prototyping
    • if you run your project with features implemented with blueprint, there would be much cost:
      • view or diff blueprint asset → time to open Unreal Editor
      • merge blueprint asset → time to open Unreal Editor & re-work the changes
        (+ effort to remember what were the changes)
      • …etc
  • the UFUNCTION specifier BlueprintImplementableEvent
    • is fit in this purpose
    • will help your prototyping with unit of function

※ for more information about BlueprintImplementableEvent specifier, see the reference #3

1
2
3
/// This function is designed to be overridden by a blueprint.  Do not provide a body for this function;
/// the autogenerated code will include a thunk that calls ProcessEvent to execute the overridden body.
BlueprintImplementableEvent
  • at ObjectMacro.h we can find the enum of BlueprintImplementableEvent and its comment
  • the access specifier of function using BlueprintImplementableEvent must not be private
    • which means, it must be public or protected
  • you cannot implement the body of function in cpp
    • you must implement the body of function in blueprint
    • as UBT(unreal build tool) makes an implementation of the BlueprintImplementableEvent function, your cpp implementation causes error

example

  • suppose you want to make a simple feature
    • when the game starts, a widget is shown at the center of screen
    • the widget is kind of textblock, which contains a text like “Hello World !”
  • let us call the function in BeginPlay()
    • when the player controller is created, the NotifyTestFunc() will be executed

  • add a variable for widget
    • create blueprint class of the cpp player controller
    • it can be assigned at the inspector of Class Defaults
  • you can implement the function in Event Graph
    • let us just show a screen debug message
  • prepare game mode
    • set the game mode, character and player controller as ours
  • screen debug message is shown well
  • now let us show the widget
  • create a widget and add it to viewport
  • what happened ? I cannot see any widget
  • let us see the Message Log
  • the log says, there is access to None at Add to Viewport node
    • add breakpoint at the node and find why
  • absolutely this could be a crash in cpp code
    • with blueprint, we can keep going unless shuting down the editor

  • oh, the Target is None
    • that is why the message log is created
  • as we did not assign the class of widget, Create User Widget node returned None
  • let us create a widget and assign it


  • now it works !
    • almost work is written with blueprint and there is only one cpp compilation
    • this development process can improve your productivity
  • the rest of work is converting the blueprint things into cpp code

wrap-up

  • Hot Reload is fast enough to develop personal project
    • if you do not take much time to compile cpp, there is no significant benefits to using blueprint
    • time to compile cpp can be similar much than blueprint one
  • blueprint using BlueprintImplementableEvent is useful
    • if it takes more than 5~10 minutes whenever cpp compiles, you should consider blueprint
    • but, you need to convert blueprint into cpp when it completes
  • as a result, the workflow I recommend you is:
    • design a feature as one function with BlueprintImplementableEvent
    • implement the function with blueprint
    • remove blueprint implementation & implement the function with cpp

UnrealEngine FName anatomy


what FName is

  • one of the 3 main string types in Unreal Engine, which is used for indicating individual object in game
  • as its purpose, FName do not have features for string manipulation such as trim, reverse…etc.
  • it would be better to consider FName is a literal index rather than a digital index

case-insensitive

  • you may have seen the expression, “FNames are case-insensitive”, which means you cannot make more than one FName with the same alphabet arrangement
  • for example, if you already have an object its name is “Sheri”, you cannot make an object its name is “sheri”. let us see below:
  • why this happens ? find it out in the code
  • we can find the phrase at the ContentBrowserUtils::IsValidObjectPathForCrate()
    • the function validates whether new object can be created in certain directory
  • as the comment says, the phrase is shown when there is already an object with the same path
    • in other words, you can create an object with the same name in different path
  • yes, not only object, folder is also affected with the rule

FName as a hash value

  • now, you should have a question:
    • “how does Unreal Engine save the object path ?”
  • we can assume that may be not literal method, rather hash method
    • because literal method would tell us that upper case differs from lower case
  • digging one step, we can find something strange
  • as we saw, the warning pharse is shown when there is already an object with the same path
    • we can see returning some object ( that is not nullptr ) in picture above
  • ObjectPath does not have the identical indices
    • especially, ComparisonIndex and DisplayIndex
    • strangefully, DisplayIndex indicates the intended string, other does not

※ more information about the indices in #2 reference


  • digging one step more, ComparisonIndex is set by one of FName that is created earlier
    • it may be confusing, let us summary as table
String ComparisonIndex
Sheri (AssetName) 884751
/Game/ThirdPersonCPP/Blueprints/Sheri.Sheri (ObjectPath) 884754
sheri (AssetName) 886628
/Game/ThirdPersonCPP/Blueprints/sheri.sheri (ObjectPath) 886631

※ the value of index is not consistent. it can have a different value each time
※ more information about the names and pathes in #3 reference

lower-case string compare

  • digging one step more !!
    • why did later one set by earlier one ?
  • let us look at StaticFindObjectFastInternalThreadSafe()
    • the function finds and returns an certain object(or package) depending on parameters
  • at line #588, there is an == operation between two FNames
    • if they are the same, the expression must become true
  • then, we got the one last destination FName::operator==()
    • actually, we should go to StrnicmpImpl() due to the callstack below
    • FName::operator==() → FNameHelper::EqualString() → StringAndNumberEqualsString() → FPlatformString::Strnicmp() → StrnicmpImpl()
  • in this function, each character of each string is compared in lower case
  • now we understand why Sheri and sheri are identical in using FName

wrap-up

  • FName is not identified with case
    • we could see it with Sheri and sheri example
    • every FName is compared in lower case
  • FName is used with index format
    • for effectiveness, real string is cached and is accessed with index
    • there are two indices, ComparisonIndex and DisplayIndex
  • FName duplication test is relying on path name
    • you can have two objects such as /Game/Sheri/Umbrella and /Game/Donita/Umbrella
    • this means that the same AssetName can exist multiple times in one project

Retrospection 2019

overview

it is first time to write retrospection as a post. with starting a job for game programming and wraping up my university activity, I thought it is good time to write it. regardless of anyone, every new year is the hardest one. yeap, this year was so hard and eventful to me. so you can see me grumble in this post many times. anyway, that would be a retrospection too.

timeline is below:

  • being a senior year in university
  • having a role of leader in HPC Lab
  • working at a start-up company as part-time job
  • moving in Seoul for work
  • getting a full-time job at PUBG

graduation

being a senior year, as same as usual university, I had to do several tasks for graduation. some of them are easy, but others are not. that below is why:

  • internship as credit (-> internship issue)
    in my university, student must have an internship for essential credit. in other words, students did not have internship cannot graduate, even they are hired with regular job. making matters worse, only an internship satisfying terms of agreement made by the university is approved to get the essential credit. otherwise, the student cannot get the essential credit.

  • graduation project
    like the internship issue, student must complete an project for essential credit. the scale of project is usually forced to be big as possible as by professors, which have right to pass project. that means, you cannot throw away the graduation project with the mind “I do not care that one bit of shit.”.

first of all, the two issues have been solved…but there were so much pain. X( …especially the internship issue tortured me for 1~2 months.

the agreement mentioned above should be reviewed by company’s legal team and personnel team. in worst case, they could reject the agreement. even they accept the agreement, university could reject your request of essential credit for the reason the internship period is not fit in some schedule they planned. crap ! though students should take care of everything unnecessary, university insists this system help the students get a job. actually, I could not get the essential credit with my first internship for complicated reasons. I do not want to tell about it more…just disgusting. university made me fight to company and themselves. early 2019 was that time mentally weak.

graduation project, this one bullied me too. I could not choose my team member by myself, and the members to go with were very passive. that is, they did not proceed the project on themselves. I had to take care of both development and team management. although I had many tasks to do, the project has been made most by me. anyway, on developing the project, I found this funny moment: https://twitter.com/Thanang/status/1171038097024307200?s=20 my graduation project was about automation of making game agent. mainly used Tensorflow and BizHawk, Tensorflow as machine learning framework and BizHawk as reinforcement learning environment. you can visit the repository in my github: https://github.com/BaeMinCheon/BizHawk and https://github.com/BaeMinCheon/street-fighter-agent


lectures

took various lectures, too. specially, lecture multicore-programming (-> MP) and virtual-reality-programming (-> VRP) are remained in my memory. in MP, I learned CUDA and could improve it with several projects. these experiences gave me insight of multi-thread things. and it helped me when the multi-thread subject were appeared at job interview in future. I learned VR and AR with intuitive explanation in VRP. thanks to the professor, I could get more understanding on Unity Engine and its usage. this helped me after when I use Unity Engine at start-up part-time job. the project repo is: https://github.com/beat-kids


laboratory activities

in previous year, 2018, I entered laboratory specialized in high performance computing (-> HPC) on my foot. mid 2018, I started a role of undergraduate researcher in the HPC lab. from the time, studying machine learning and multi-core programming, I got much experience and intense feedback from professor. though this activity was light than a graduate course, I could learn many things useful: how to research, how to present and how to write English. feeling being respected, I could do my best on HPC tasks and get more skills.

time goes on, senior researchers graduated by ones and twos, leader position came to me. not having any reason to refuse it, I accepted the position. and I started to fix almost everything in HPC. especially laboratory workflow and infra. I recommended slack as the messenger and trello as the issue tracker (for kanban-board). taught members how to use git and gitlab. due to these tries, we could work together more efficiently. setting up small infra was enough for me to apply computer network techs. installing APs and setting internal route protocol, turning and using server remotely…etc. every work was associated to network theory and became a good review.


start-up & job hunting

kept to follow those who are in game development field on twitter, I could get various information about game development things including job post. fortunately, this activity led me to get a part-time job as Unity game programming. was a beginner in Unity game programming at that time, I was hired to do small potion of works. but it was the first time that I made money with programming, I did my best on almost things and also tried to learn skills that will be required in future. the motive might be come from self-esteem and a will to give a good impression.

at there, I developed two games and they were both for mobile platform. so I had a chance to study for mobile platform especially Android. despite Unity’s multi-platform support, there is sometimes extra work for platform specific issues. stuck in Android Studio, I suffered so many times. one of the games was about flight fight game. as only my experience about flight in game was battlefield series, I had to play some flight games such as Ace Combat series. in addition, aircraft physics was not that easy. though I thought that I am fit in this kind of job, it was not. applying theory into code is not the same level with just knowing theory. everyday I struggled for expecting what happens on aircraft physics code changes.

after end of the part-time job, as planned, I sought for job of game programming. applied to several companies: Pearl Abyss, NC Soft, Bluehole, PUBG…etc. target position was primarily the game client programmer. continued job hunting, I could join interview many times. some of them were bad enough to fail the interview, some of them were good enough to pass the interview. by the time I engaged the 5th interview in my life, taking an interview could not bother me to relax. absolutely practice makes everything fine.

topics on interview were similar regardless of what company is. in other words, what they want from fresh recruit like me. three main topics are below:

  • Object Oriented Programming theory (based on cpp)
    • why is it needed ?
    • what is virtual function and how it works ?
    • show me explanation of function overriding
      …etc
  • Computer Science / Engineering theory (related to game)
    • what is multi-thread and race condition ?
    • tell me difference between mutex and semaphore
    • why a cube is used for view projection in graphics pipeline ?
      …etc
  • Project Experience (as a team)
    • what did you think learn from the project experience ?
    • why did you do this (on the code / on the feature …etc) ?
    • talk about the most critical situation in the project and how did you overcome ?
      …etc
  • Work Experience 😂 (but it is appealing one too…)

uneasy yearly rent

after the hectic job hunting, I got informed of acceptances from each company. had to choose one among companies, finally I decided to join the PUBG. as Korean office of PUBG is located in Seoul, that was the time to move into Seoul ! I lived in Chungcheong-Namdo for almost whole life. born in there, graduated schools in there, even attended university in there ! these events made me wish to get out of this little world. however, the move was not that easy going.

everyone recommends you yearly rent (“전세”) to save the money. ummm, that is right answer. but you may be suffered with horrible documents and tasks for “전세” loan. a job beginner like me cannot apply the loan from bank due to lack of career. even the loan from government asks you for strict conditions. while on dealing with these difficulties, you might give up and settle to monthly rent (“월세”).

in my case, PUBG provided a fund for renting house. so I could manage to rent a small room near the office as “전세”. unless it, I also had to settle to “월세”. keep in mind that looking for a room with “전세” using any loan is a really hard work needed patience. if you have no time and no patience, just starting as “월세” is not that bad option. particularly for job beginner like me.


PUBG life

it has been 4 months after I started a full-time job in PUBG. there were so many happenings within that short period. I cannot tell the whole stories now, but someday I will tell some of them. just now, I do contents programming for console platform PUBG. XBox One and Play Station 4 are my playground and workplace at the same time. these days I am quite good at handling game-pad, differently before. also been familiar to low-spec HW causing delay of work. ;D

as I expected, many employees in game company are like nerd. many of them love to play games or develop games. they are knowledgeable to games than the average people. just…well…I wanted to meet these people who have these pure mind that makes games with a hope to make users be fun. the truth I can work with them made me excited. it lasted quite long time. and also game programmers are usually interested in physics things. now I am happy that have someone to talk about these subjects.

task is not easy, but enough to challenge. almost everyday I learn something new. there are chances to conversate with foreign programmer. now I know they are usual human beings, too. their thinking is not that different from us (korean programmer), and they can either make basic faults. as a result, I met someone or something new many times, and tried to understand he/she/it. so…during the PUBG life in 2019, I think I could have developed my view to the world.


wrap up

this year 2019, was the hardest one to me. I had to deal with so many tasks in simultaneously such as university works, internship, job hunting, personal development project, even my job. I only wanted to focus on developing something, however, there was always something else in society life. anyway, it was successful to harvest my effort for 4 years in university. I also achieved my target: be a FPS game developer. cheers. 🍺

next year, I might be able to do these tasks below:

  • university graduation and degree acquisition
  • practical and useful project about Unreal Engine
  • hanging out with more people
  • getting pretty good evaluation on peer review at work
  • helping the new comer to game development industry

EOF.

Shared folder in WSL

  • this post covers
    • how to share a folder in wsl
  • environment
    • Windows 10 / Home
    • WSL / Ubuntu 18.04 LTS
    • Visual Studio Code

pre-task

  • install WSL in your Windows 10
    • open the Microsoft Store
    • search for Ubuntu
    • click Ubuntu 18.04 LTS
    • get and install it
  • prepare the environment
    • initialize your wsl
  • make a folder in some directory on Windows
    • ex) D:\Code\LinuxShare
  • make a link in some directory on WSL
    • format) ln -s /mnt/[partition]/[folder...] [link-name]
    • ex) ln -s /mnt/d/Code/LinuxShare share-with-windows

make-file

  • make a text file on Windows side
    • ex) D:\Code\LinuxShare\test.txt
  • check out the text file on WSL side
    • ex) ~/share-with-windows/test.txt
  • edit the text file and save it on WSL side
    • ex) hello WSL !hello Windows !
  • check out the text file on Windows side

typing-and-compiling

  • make a c file and edit it on Windows side
    • ex) D:\Code\LinuxShare\test.c
  • compile the c file and execute it
    • ex) ~/share-with-windows/test.c
  • you can now type texts on Windows and compile that on WSL
  • also output file, a.out will be seen on Windows side

UnrealEngine linux server build


overview

  • if you want to seperate the game into client and server
    • mostly, the clients would be executed on windows
    • as the server is up to you, you can select more efficient option
      • in aws, linux server instead of windows to save cost
  • so it is needed to build linux server, but you can use cross compilation
    • this makes you can build linux server on windows
  • in this post, I suppose you have already an unreal engine built from source code and test project
    • especially, I used 4.21 version

setup

  • download the proper toolchain from this document
    • in my case, clang-6.0.1-based toolchain is needed
  • execute the toolchain installer
    • you do not have to do extra works when your engine version is equal to or over 4.14
    • if not, reference the document mentioned for the details
  • in the test project, edit the DefaultEngine.ini of [ProjectRoot]/Config/DefaultEngine.ini
    • add the code below
    • the code will add configurations for linux version build
1
2
[/Script/LinuxTargetPlatform.LinuxTargetSettings]
TargetArchitecture=X86_64UnknownLinuxGnu
  • right click uproject and select Generate Visual Studio project files
    • open sln and build the test project with Development Editor & Win64

build

  • double click uproject and you would see the test project on unreal editor
  • select Development in File/Package Project/Build Configuration
  • select Linux in File/Package Project
    • choose an arbitrary directory for saving the package
    • in my case, I created Packages folder in project directory and use it
  • after packaging, you can see the directory like this
  • open sln and build the test project with Development Server & Linux
  • you can see the [ProjectName]Server build, which will be executed on linux
  • copy the [ProjectName]Server into package binary folder
    • now you can execute [ProjectName]Server on linux

usage

  • in this post, I will show you an example with wsl
    • I recommend to make shared folder for sharing files
    • if you do not know about it, read this post
  • I used a shared folder called LinuxShare for sharing the package files
  • there are build files in package binary folder
    • [ProjectName] is build file from Game build target, which cannot be executed for absense of graphics api
    • [ProjectName]Server is build file from Server build target, which is copied by you
  • execute server build with option 127.0.0.1 -log on wsl(linux)
  • execute client build twice with option 127.0.0.1 -log -windowed resx=720 resy=480 on windows
    • you can see the same result that we saw in previous post

Differences in UnrealEngine build targets


overview

  • I suppose you already have the unreal engine built from source of 4.21 version
    • if you do not, read the custom-unreal-engine-build post
  • once you build the UE4 project with option Development Editor & Win64
    • you can find [EngineRoot]/Engine/Binaries/Win64/UE4Editor.exe and execute it
  • in this window, you can create project using your custom engine
    • create a Third Person template project for testing several build targets in this post

build-targets

  • in unreal engine, “build (file)” means the executable file or library file made from source code

    • ex1) UE4Editor-[ProjectName].dll of Editor build target
    • ex2) [ProjectName]Client.exe of Client build target
    • ex3) [ProjectName].exe of Game build target
  • there are four build targets frequently used

    • Client
    • Server
    • Game
    • Editor
  • Client

    • this target is used for building only client
    • it has several features especially displaying screen
    • so if the system does not have any graphics API, it cannot be executed
  • Server

    • this target is used for building only server
    • it does not have several features especially displaying screen
    • so regardless of graphics API, it can be executed
  • Game

    • this target is used for building whole game
    • it has all features from Client and Server targets
    • so a build from this target can be used as client, and server too
      • it is not recommended for the commercial game project because user could get the server feature
  • Editor

    • this target is used for executing the game on unreal editor
    • only the build from this target can be opened in unreal editor
      • also, unreal editor only can open this build, which means packaging impossible
    • totally, it has all features from Game

packaging

  • because build files do not contain unreal assets, it cannot be executed alone
    • we have checked out what happens when only using a build file in previous post
    • so, executing the game from any build file, you need to package unreal assets used in the project file
    • and packaging can be done in unreal editor, not the source code editor such as visual studio IDE
  • there are some prerequisites for pacakaging the test project
  • open the sln for the test project and build it with Development Editor & Win64
    • and press F5 to start debugging
  • you would see the Third Person default map with unreal editor
  • open the Project Settings window and find Maps & Modes tab
    • set every map with the default map
  • find Packaging tab
    • add the default map to the List of maps to include in a packaged build
  • write target config files for Client and Server targets
  • right click uproject and select Generate project files

  • re-open the sln and build the test project with each solution configuration

    • Development & Win64
    • Development Client & Win64
    • Development Server & Win64
  • now you can see the three build files

  • open the test project with unreal editor

    • way1) double click uproject
    • way2) execute [EngineRoot]/Engine/Binaries/Win64/UE4Editor.exe and select the project
  • select Development in File/Package Project/Build Configuration
  • select Windows (64-bit) in File/Package Project/Windows
    • choose an arbitrary directory for saving the package
    • in my case, I created Packages folder in project directory and use it
  • after packaging, you can see the directory like this
  • as we packaged the project with Development the executable files are the same
  • copy the build files into the Packages/WindowsNoEditor/[ProjectName]/Binaries/Win64
    • [ProjectName].exe
    • [ProjectName]Client.exe
    • [ProjectName]Server.exe
  • run the command prompt and move to the Packages/WindowsNoEditor/[ProjectName]/Binaries/Win64
    • execute each build file with some options for knowing what happens inside
  • execute Game build file with options -log -windowed resx=720 resy=480
    • -log option makes the game print logs
    • -windowed option prevents the game from running as full-screen
  • you can terminate the game
    • way1) click X on the right of game window
    • way2) press a grave accent and type exit
  • execute Client build file with options -log -windowed resx=720 resy=480
    • you can see the same result of Game build
  • execute Server build file with options -log
    • you can see there is no game screen with Server build

game-client-server

  • I mentioned Game as “it has all features from Client and Server targets”

  • execute Game build 3 times with options below

      1. -server 127.0.0.1 -log -windowed resx=720 resy=480
      1. 127.0.0.1 -log -windowed resx=720 resy=480
      1. 127.0.0.1 -log -windowed resx=720 resy=480
  • the first game acts as (client + server) and other games act as client

    • this means Game target = Client target + Server target
  • execute Server build with options below

    • 127.0.0.1 -log
  • execute Client twice with options below

      1. 127.0.0.1 -log -windowed resx=720 resy=480
      1. 127.0.0.1 -log -windowed resx=720 resy=480
  • the first game acts as server and other games act as client
    • you can see server do not have a screen

UnrealEngine custom build

  • recommend to read first
  • this post covers
    • why we need the custom unreal engine
    • how to access to unreal engine code
    • how to build and configure our custom unreal engine
  • environment
    • Windows / 10
    • Visual Studio IDE / 2017 Community

overview

  • using unreal engine with the Epic Games Launcher means that you can use some parts of unreal engine
    • because, engines provided from Epic Games Launcher are lack of some features ( find more at here )
    • especially, you can only use Client and Server build target with custom unreal engine
  • if you want to use whole of unreal engine, you need to build unreal engine from source code
    • making a project with custom engine, Epic Games Launcher recognizes the project but not the version of engine
    • you can see the Other on the screenshot above, which means that versioning is not meaningful no more
  • for example, suppose you need to seperate your game project into client and server
    • that means, client version of your game only has the feature for client and vice versa
    • build targets supported by engine from Epic Games Launcher are only Game and Editor so you cannot

access

  • accessing to unreal engine repository needs some process below
  • visit epic games page and sign in
  • click PERSONAL in the combo box on your nickname and click CONNECTED ACCOUNTS
    • click CONNECT in the GITHUB box and sign in with your github account
    • then, some mails would be sent to your email and accept them
  • now you can find that you have entered the Epic Games organization
  • visit the unreal engine repository and download or clone it
  • if you want to make custom engine based on a specific version, select the proper branch
  • now you are ready to build custom engine

build

  • before starting, there are some requirements to visual studio IDE
  • execute visual studio 2017 and click Tools/Get Tools and Features...
    • in Individual components tab, you should check the components below
      • .NET Framework 4.5 things
      • .NET Framework 4.6 things
      • VC++ 2015 for desktop things
  • right click the Setup.bat in engine root folder and select Run as administrator
  • execute command prompt and move to engine root folder
    • type GenerateProjectFiles.bat -2017 and enter
    • now you can see UE4.sln is generated and open it with visual studio 2017
  • right click UE4 project and select build
    • it takes soooo long time ( about 1~2 hours )

usage

  • launch any engine on Epic Games Launcher
  • create some project
  • right click uproject and select Switch Unreal Engine version...
  • if the build was successfully done, there is the engine root in combo box
    • if not, find and choose the engine root directory
  • select proper one and it starts generating project files
  • open the [ProjectName].sln and you can check out the UE4 in solution explorer
  • even you would find the Client and Server options in solution configurations
    • this process is required whenever you want to use custom engine
    • hooh ! now you can use your own custom unreal engine !

What is UnrealEngine build target

  • this post covers
    • what is the build target in unreal engine
    • why we need the several build targets
  • environment
    • Windows / 10
    • Unreal Engine / 4.19.2
    • Visual Studio IDE / 2017 Community

overview

  • create new project with Basic Code in cpp tab
  • then you can see the directory like this
  • open the [ProjectName].sln and check out the csharp files whose name are ending up with Target.cs
  • now you may wonder…
    • what the Type = TargetType.Game means
    • what the heck is UnrealBuildTool
    • what is difference between [ProjectName]Target and [ProjectName]EditorTarget
  • do not hurry, first of all, we gonna learn about the build targets

solution-configuration

  • most of you may have developed the game with no manipulation of Solution Configurations
  • when you folds it out, there are several options and each option is explained in this document detailed
    • DebugGame and Development : build output is stand-alone binary file, which has exe extension
    • DebugGame Editor and Development Editor : build output is dynamic link library, which has dll extension
    • Shipping : build output is stand-alone binary file, which has exe extension
  • the difference between
    • DebugGame and Development : the level and depth of debugging features
    • DebugGame, Development and Shipping : output of Shipping is more optimized for the reason of absence of command prompt and screen debug, etc. but, having no assets for the level presentation, both cannot be executed normally

build-target

  • yep, you have seen the Solution Configurations and what they do
  • and there is the way to change the behavior of each configuration by editing the Target.cs files
  • let us change the text Editor into Game in [ProjectName]Editor.Target.cs
  • remove the Binaries folder for checking the build output
  • build our project with Development Editor
  • look at the build output, what happened ? exe file has been generated, not the dll

  • okay, now I would think it is time to tell you how the build works

    • when you select DebugGame or Development, unreal engine does the build based on [ProjectName].Target.cs
    • also, when you select DebugGame Editor or Development Editor, unreal engine will build based on [ProjectName]Editor.Target.cs
    • and the Type in Target.cs file is a key value of build configuration, which is read by UnrealBuildTool
  • as a result, there is no significant difference except for the file names
    • first 5 files are built with Development and Test419.Target.cs with Type = TargetType.Game
    • later 5 files are built with Development Editor and Test419Editor.Target.cs with Type = TargetType.Game

why-it-needed

  • this structure can help you customize build configurations
    • if you need to build for several enviroments, take care of the target files
    • there are many options not only Type value, find at this document
  • typically, the target file is used for building an unreal server
    • at that time, we will use [ProjectName]Server.Target.cs with Type = TargetType.Server
    • because, in the production level, we need a server executing unreal dedicated server

further

  • I will write about unreal server build and combination with aws game lift
  • in the following contents, this post should be useful for you
  • there is a good QnA for these subjects