Sunday, November 17, 2019

C++ 11 features

This is auto translation of what I summarized.

auto
The auto keyword allows the type of the lvalue to be determined by the type of the rvalue. When using STL, mainly vector <int> :: iterator iter = vectorData.begin (); I had to code it this way, but now I can easily code it with auto iter = vectorData.begin ();


constexpr
constexpr gives you a hint that an expression can be determined at compile time, allowing you to write code that couldn't be optimized or used previously. For example, for arrays, the size must be determined by the compilation type. For example, the following code was not possible.

int array [getPlayerCount () + 1];

At this time, even if getPlayerCount function is a constant expression, it could not be compiled.

int getPlayerCount ()
{
    return 3;
}

However, you can use the above syntax by using the constexpr keyword to give the compiler a hint that this function can be determined at compile time. Like this


constexpr int getPlayerCount ()
{
    return 3;
}

This allows you to use a syntax like int array [getPlayerCount () + 1]. Also as square or cubic

constexpr int cubic (int x)
{
    return x * x * x;
}

In this case, cubic (2) can be optimized because the cubic result is determined by the compilation type and can be directly assigned.

initializer list
The initialization list is the use of {}.
int myArray [3] = {1, 2, 3};

vector <int> myVector = {1, 2, 3}; <-Can be initialized like this.

To use in a function

void foo (const initializer_list <int> & v)
{
    for (auto iter = v.begin (); iter! = v.end (); ++ iter)
    {
        // can access the contents of v with iter
    }
}

uniform initialization
extended curly brace initialization

dog d {3}; If you use, you will find the first choice below first, and if not, it will look in the order of 2 and 3.

class dog {
public:
    int age; // 3rd choice

    dog (int a) // 2nd choice
    {
    }

    dog (const initializer_list <int> & vec) {// 1st choice
    }
};

foreach
In c ++ 11, you can use the following syntax for foreach:

vector <int> myVector = {1, 2, 3};
for (auto element: myVector)
{
    // element is an element of myVector
}

nullptr
The old NULL was equal to zero. Previously, I was using NULL, but I wonder why nullptr appeared as a keyword. When there are two functions as follows:

void foo (int a);
void foo (char * p);

foo (NULL); <-Function calls like this can be ambiguous.

in c ++ 11

foo (nullptr); It can be understood as calling void foo (char * p) function.

enum class
Since the enum itself was an int it could cause problems in the comparison syntax. For example

enum playerState {first, second};
enum itemState {itemA, itemB};

playerState A = first;
itemState B = itemA;

if (A == B) <-true even though it is of a different type.

c ++ 11 has enum class

enum class playerState {first, second};
enum class itemState {itemA, itemB};

When there is

The following syntax if (A == B) causes a compilation error unless you define the == operator of playerState, which allows for stronger type checking.

static_assert
You can use the asset at compile time. For example

static_asset (sizeof (int) == 4); This can be checked at compile time.

delegating constructor

In the case of constructors, there was a pattern of creating and calling a function when there was a common part. For example

class Player
{
public:
    Player () {
    }

    Player (int age)
    {
    }

    Player (int age, int height)
    {
    }
};

If you need common code in the constructor, create a function called init or base to call the common part of each constructor.

    Player () {

        init ();

    }



    Player (int age)

    {

        init ();

    }



    Player (int age, int height)

    {

        init ();

    }


In this pattern, a function called init is a generic function and can be called at other times than at creation time. (You can call it even if you hide it as private.)

c ++ 11 supports constructor delegates.

Player (int age): Player () {… };

Can be called: This way, you can keep the base code in Player () and take advantage of the constructor delegates. And since this is not a regular function, it cannot be called at any other time.

override
In c ++ 11, the keyword override is added, and if you want to override a parent class's function in a child class, you can explicitly specify override to avoid ambiguity.

class player {
    virtual void A (int);
    virtual void B () const;
};

class footballPlayer: public player {
    virtual void A (float) override; <-Compile Error
    virtual void B () override; <-Compile Error
};

final
You can make a class non-inheritable. For example

class Player final
{
};

In this case, the Player class cannot be inherited.

class FootballPlayer: public Player
{
};

Can not. Can be applied to functions

class Player
{
    virtual void foo () final; <-This function cannot be overridden.
};

default constructor
If you define the constructor of the class after that, if you do not create a default constructor separately, an error occurred. You can avoid the error without writing the default constructor by

class Player
{
    Player (int age);
    Player () = default; <-This syntax tells the compiler to create a default constructor.
};

delete
There is an implicit cast in C ++, which can lead to function calls that contain unwanted implicit casts.

class Player
{
    Player (int age);
};

Player player 10;
Player player (3.1415); <-Available.

To prevent this

class Player
{
    Player (int age);
    Player (double) = delete; <-Now Player player (3.1415); An error occurs at
};

lambda
[] (int x, int y) {… };

==============================================

auto
auto 키워드는 rvalue의 타입에 따라 lvalue의 타입이 결정될 수 있도록 한다. STL을 사용할 때 주로 vector<int>::iterator iter = vectorData.begin(); 이런식으로 코딩을 해야 했었는데 이제는 다음과 같이 auto iter = vectorData.begin();으로 쉬운 코딩이 가능하다.

constexpr
constexpr은 expression이 컴파일 타임에 결정될 수 있다는 힌트를 주어 최적화 또는 기존에 사용할 수 없었던 코드를 작성할 수 있도록 해준다. 예를 들어 배열의 경우 사이즈는 컴파일 타입에 결정되어야 한다. 예를 들어 다음과 같은 코드는 불가능했었다.

int array[getPlayerCount() + 1];

이때 getPlayerCount 함수가 다음과 같이 상수식이어도 컴파일이 불가능했다.

int getPlayerCount()
{
    return 3;
}

하지만 constexpr 키워드를 사용해 컴파일러에게 이 함수가 컴파일 타임에 결정될 수 있다는 힌트를 주면 위 구문을 사용할 수 있다. 다음처럼

constexpr int getPlayerCount()
{
    return 3;
}

이렇게 하면 int array[getPlayerCount() + 1]과 같은 구문 사용이 가능하다. 또한 square 또는 cubic과 같이

constexpr int cubic(int x)
{
    return x * x * x;
}

이때 cubic(2)라고 하면 cubic의 결과값이 컴파일 타입에 결정되어 바로 대입 가능하므로 최적화가 될 수 있다.

initializer list
초기화 리스트는 { }을 사용하는것을 말한다. 

int myArray[3] = { 1, 2, 3 };

vector<int> myVector = { 1, 2, 3 }; <- 이렇게 초기화 가능하다.

함수에서 사용하기 위해서는 

void foo(const initializer_list<int>& v)
{
    for ( auto iter = v.begin(); iter != v.end(); ++iter )
    {
        // iter로 v의 내용 접근이 가능하다.
    }
}

uniform initialization
curly brace initialization을 확장 했다.

dog d{3}; 을 사용하면 아래에서 가장 먼저 1st choice를 찾고 못찾으면 순서대로 2, 3순서대로 찾는다.

class dog {
public:
    int age;    // 3rd choice

    dog(int a) // 2nd choice
    {
        
    }

    dog(const initializer_list<int>& vec) {  // 1st choice
    }
};

foreach
c++ 11에서는 foreach를 위해 다음과 같은 구문 사용이 가능하다.

vector<int> myVector = {1, 2, 3};
for ( auto element : myVector )
{
    // element는 myVector의 요소    
}

nullptr
기존 NULL은 0과 같았다. 기존에 NULL을 사용해서 잘 사용하고 있었는데 왜 nullptr이 키워드로 등장했는가 의문이 들 수 있는데 다음과 같이 함수가 두 개 있을 때

void foo(int a);
void foo(char* p);

foo(NULL); <- 이와 같은 함수 호출은 모호할 수 있다.

c++11에서는 
foo(nullptr); 로서 호출하며 이때 호출은 void foo(char* p) 함수를 호출하는 것으로 이해할 수 있다.


enum class

enum 자체가 int 였기 때문에 비교 구문에서 문제가 생길 수 있었다. 예를 들어 

enum playerState { first, second };
enum itemState { itemA, itemB };

playerState A = first;
itemState B = itemA;

if ( A == B ) <- 실제로 다른 타입임에도 불구하고 true가 된다.

c++11에는 enum class가 있으며

enum class playerState { first, second };로 할 수 있으며
enum class itemState { itemA, itemB };

가 있을 때

다음과 같은 구문 if  (A == B)는 playerState의 == 연산자를 정의하지 않은 이상 컴파일 오류가 발생하게 되어 좀 더 강한 타입 검사를 할 수 있게 된다.


static_assert
컴파일 타임에 asset를 사용할 수 있게 된다. 예를 들어

static_asset( sizeof(int) == 4 ); 와 같이 컴파일 타임에 검사 할 수 있도록 해준다.


delegating constructor
생성자의 경우에 공통 부분이 있을 경우에 따로 함수를 만들어서 호출하는 패턴이 있었다. 예를 들어

class Player
{
public:
    Player() {
    }

    Player(int age)
    {
    }

    Player(int age, int height)
    {
    }
};

가 있을 때 생성자에서 공통의 코드가 필요하면 init 혹은 base라는 함수를 만들어 각 생성자에서 호출하여 공통 부분을 호출했다.

    Player() {
        init();
    }

    Player(int age)
    {
        init();
    }

    Player(int age, int height)
    {
        init();
    }

이 패턴에는 init이라는 함수가 일반 함수이며 생성 타임이 아닌 다른 경우에도 호출될 수 있다는 점이다. (private으로 가려놓아도 호출할 수 있긴 하다.)

c++11에는 생성자 델리게이트를 지원한다.

Player(int age) : Player() { … };

와 같이 호출할 수 있다. 이렇게 되면 기본 코드는 Player()에 넣어놓고 생성자 델리게이트 기능을 활용해서 베이스 코드를 유지할 수 있다. 그리고 이것은 일반 함수가 아니므로 다른 타임에 호출될 수 없다.


override
c++11에는 override라는 키워드가 추가되었고 자식 클래스에서 부모 클래스의 함수를 오버라이드 하고 싶은 경우에 명시적으로 override를 적어 주어 모호함을 피할 수 있다.

class player {
    virtual void A(int);
    virtual void B() const;
};

class footballPlayer : public player {
    virtual void A(float) override; <- 컴파일 에러 발생
    virtual void B() override;  <- 컴파일 에러 발생
};


final
클래스를 상속 불가능하게 만들 수 있다. 예를 들어

class Player final
{
};

의 경우에 Player 클래스를 상속할 수 없다.

class FootballPlayer : public Player
{
};

를 할 수 없다.

함수에도 적용할 수 있는데

class Player
{
    virtual void foo() final; <- 이 함수는 override할 수 없다.
};


default constructor
클래스의 생성자를 정의하게 되면 그 이후부터 기본 생성자를 따로 생성하지 않으면 오류가 발생했는데 다음과 같이 작성하면 기본 생성자를 작성하지 않고도 오류를 피할 수 있다.

class Player
{
    Player(int age);
    Player() = default; <- 이 구문으로 컴파일러에게 기본 생성자를 만들도록 지시할 수 있다.
};


delete
C++에는 암시적 형변환이 있는데 이것 때문에 원하지 않는 암시적 형변환이 포함된 함수 호출이 이루어질 수 있다.

class Player
{
    Player(int age);
};

Player player(10);
Player player(3.1415); <- 가능.

이것을 막기 위해

class Player
{
    Player(int age);
    Player(double) = delete;   <- 이제 Player player(3.1415); 에서 에러가 발생한다.
};


lambda
[](int x, int y) { … };

Blueprint is for decision making and c++ is for implementation detail.

Long time ago, I created a tool that is allow you to create a FSM visually. 

<PAI Design Tool. I created it long time ago. more detail http://www.thisisgame.com/webzine/series/nboard/212/?series=99&n=57612 my article here.>

On PAI, game designer focus on the decision making and programmer(me) focus on the implementation detail.

When I use blueprint and c++ in unreal engine 4, I have same feeling now.

Wednesday, November 13, 2019

Recently I'm playing around with Unreal Engine 4.

Really fun but I have to think which method I should use because there are too many different choices to achieve same thing. I'll summarize after I finish some work.

Tuesday, November 5, 2019

Parallel programming is really powerful.

Making a digital human usually needs lots of image processing. Size of image is normally greater than 3000 x 5000 and around 10 images of these, combining takes few seconds or minutes.

When I implement something I usually implement logic as quickly as possible and then optimize it. I checked my image processing logic took around 2 seconds.

for ( int y = 0; y < height; ++y ) {
    for ( int x = 0; x < width; ++x ) {
    {
        // processing logic here
    }
}

<<Traditional 2D image processing driver code>>

my processing logic was simple, just grab pixel from different textures and then combine it and put it on some specific texture. Processing logic could be parallelized. so I changed it and profiled. 

Original logic took 2 seconds and new parallelized logic took 0.3 seconds which is 7 times faster!

How to change
first of you should include ppl.h.

#include <ppl.h>

parallel_for is the function what we are going to use.

parallel_for(0, 100, [](int value) {
    // processing logic here, order of value is not determined. this block is called in parallel
});

lambda is called 100 times and order is not determined. like we saw in the above code blocks. Traditional 2D image processing takes x, y for accessing pixel. but parallel_for takes 1D value. we can use mapping function. (this is also traditional converting logic in gaming industry)

const int linearCount = height * width;
parallel_for(0, linearCount, [&](int linearIndex) {
    int y = linearIndex / width;
    int x = linearIndex % width;

    // processing logic here.
} );

using / and % operator, we can get x, y from 1D value. and whole logic can be parallelized.

Try and apply it to your project!
This is very simple and easy way to improve performance :)

Another tip
Recently performance counting in c++ is really easy.

auto t1 = std::chrono::high_resolution_clock::now();

// logic

auto t2 = std::chrono::high_resolution_clock::now();
auto t = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();

Unity : FPS Microgame new feature and gameplay.

Finally I added a Tracer's blink skill to the player.



Implement blink was really easy.

// tracer blink.
if (isGrounded && m_InputHandler.GetTracerBlink())
{
characterVelocity *= 10;

// make blink effect
GameObject obj = GameObject.Instantiate(trailPrefab,
transform.position, Quaternion.identity);
obj.GetComponent<VFX_Trail>().SetFollowObject(gameObject, 0.7f);
}


For trail effect I added trail effect object and 0.7 later it will be destroyed. As you can see there is a variable characterVelocity. That's a character's velocity and blink skill just boost the current velocity 10 times faster.

I added portal, weapon tuning, new blink skills and tried to play this game to make it look fun.








That is it! I hope you enjoyed this series of article. :)


Sunday, November 3, 2019

Unity : FPS Microgame Analysis -2-


Class: ProjectileBase

As you can see, ProjectileStandard has a member of ProjectileBase. ProjectileBase has a UnityAction variable, which is onShoot and it is a delegate. onShoot will be called in Shoot method. Actual logic related with Projectile is in ProjectileStandard class.

ProjectileStandard component is attached into Projectile_[WeaponName]. Let’s see how Projectile_Blaster prefabs look like.

<ProjectileStandard Component on Projectile_Blaster prefab>

<Projectile_Blaster>

Projectile has a radius for represent collision detection. You can see red sphere in the above image. That is a radius for collision detection.

Tuning for Torbjorn’s gun
If you know Overwatch (Blizzard’s game), there is a character Torbjorn. A little change makes feel different. I have just tuned some values to make a projectile to be same as Torbjorn primary gun.

<Change a scale to 1.7 from 10>

<Projectile looks much smaller than before>

Next, change Speed and Gravity Down Acceleration like down below.


<Change Speed and Gravity Down Acceleration>

If you change, the values like above then movements of projectile looks similar as Torbjorn’s primary gun projectile. In addition, WeaponControl’s Delay Between Shots value needs to be 0.5 from 0.1.

<original.gif>

<tune.gif>

Register callback
OnEnable method, we register OnShot method to the ProjectileBase’s onShot delegate. When somebody calls Shoot method in ProjectileBase then OnShot callback in ProjectileStandard is called.

Initial process for firing

<Firing Sequence>

When user fire the gun, several functions are called and onShot callback is called via delegate. In OnShot, we set shootTime, velocity, m_LastRootPosition and so on. Especially m_LastRootPosition is for tracking a position and it is used in collision detection.

Prevent firing a gun in front of the wall
User is able to fire a gun in front of the wall. When user is really close to the wall, bullet can go through walls. We need to prevent this.

if (Physics.Raycast(playerWeaponsManager.weaponCamera.transform.position, cameraToMuzzle.normalized, out RaycastHit hit, cameraToMuzzle.magnitude, hittableLayers, k_TriggerInteraction))
{
if (IsHitValid(hit))
    {
        OnHit(hit.point, hit.normal, hit.collider);
}
}


Collision Detection
Most important thing in projectile is collision detection in my opinion. Last time I mentioned that this class has a member ‘radius’. For collision detection, we use sphere shape. As you know bullet could be really fast which means it can go through the wall or enemy even player character. So just sphere vs plane or sphere vs sphere collision detection is not enough. We have to consider the time lapse.

<Time t can be really big if bullets are so fast>

In Unity has built-in functions for this and we can use it.

// Sphere cast
Vector3 displacementSinceLastFrame = tip.position - m_LastRootPosition;
RaycastHit[] hits = Physics.SphereCastAll(m_LastRootPosition, radius, displacementSinceLastFrame.normalized, displacementSinceLastFrame.magnitude, hittableLayers, k_TriggerInteraction);

foreach (var hit in hits)
{
if (IsHitValid(hit) && hit.distance < closestHit.distance)
{
foundHit = true;
closestHit = hit;
}
}

There exist multiple hits and we need to consider the closest hit.

Store m_LastRootPosition
At the end of Update method, we should store m_LastRootPosition like down below to track the last position of the projectile.

m_LastRootPosition = root.position;

Explosion and damage process
In OnHit method, we create particle, play SFX and destroy by itself. For damage process, it uses Damageable class. Using GetComponent, we get Damageable comp and then call InflictDamage function. If the projectile type is area (like bomb), calls InflictDamageInArea.

Class: EnemyController

When we talk about enemy (for AI programmer), usually enemy class has its AI states, behaviors. For instance, idle, move, attack, dead states. In this example, EnemyMobile and EnemyTurret has its own movement behavior and AI and controls Enemy with EnemyController.

EnemyController has no connection to EnemyMobile and EnemyTurret. Instead, EnemyMobile and EnemyTurret uses EnemyController. EnemyController has patrolPath, other utility functions that is common logic for both EnemyMobile and EnemyTurret.

Class: EnemyMobile

EnemyMobile is an AI class for Enemy HoverBot. EnemyMobile has 3 states which is Patrol, Follow, Attack.

Patrol data is come from the patrol game object.


PatrolPath class has pathNode. Enemy will follow the paths when the state is Patrol. As soon as enemy see the player then it change his state.

Adjusting sound pitch for movement
When the enemy moves, we change a pitch of audio based on the speed.

m_AudioSource.pitch =
Mathf.Lerp(PitchDistortionMovementSpeed.min, PitchDistortionMovementSpeed.max, moveSpeed / m_EnemyController.m_NavMeshAgent.speed);

Transitions
There are many different ways to implement FSM(Finite State Machine). By definition each state has its connections, and then connections has its condition.

If the state has no match connections then state execute his logic based on the state something like (entering, updating, exiting). In this bot example, transitions and update logics are separated to 2 functions which is UpdateAIStateTransitions and UpdateCurrentAIState. Personally, separating a transition and update logics are good idea.

void UpdateAIStateTransitions()
{
    // Handle transitions
    switch (aiState)
    {
        case AIState.Follow:
            // Transition to attack when there is a line of sight to the target
            if (m_EnemyController.isSeeingTarget && m_EnemyController.isTargetInAttackRange)
            {
                aiState = AIState.Attack;
                m_EnemyController.SetNavDestination(transform.position);
            }
            break;
        case AIState.Attack:
            // Transition to follow when no longer a target in attack range
            if (!m_EnemyController.isTargetInAttackRange)
            {
                aiState = AIState.Follow;
            }
            break;
    }
}

void UpdateCurrentAIState()
{
    // Handle logic
    switch (aiState)
    {
        case AIState.Patrol:
            m_EnemyController.UpdatePathDestination();
            m_EnemyController.SetNavDestination(m_EnemyController.GetDestinationOnPath());
            break;
        case AIState.Follow:
m_EnemyController.SetNavDestination(
m_EnemyController.knownDetectedTarget.transform.position);
m_EnemyController.OrientTowards(
m_EnemyController.knownDetectedTarget.transform.position);
            break;
        case AIState.Attack:                if(Vector3.Distance(m_EnemyController.knownDetectedTarget.transform.position, m_EnemyController.detectionSourcePoint.position) >= (attackStopDistanceRatio * m_EnemyController.attackRange))
{                   
m_EnemyController.SetNavDestination(
m_EnemyController.knownDetectedTarget.transform.position);
        }
            else
            {
                m_EnemyController.SetNavDestination(transform.position);
            }

m_EnemyController.OrientTowards(
m_EnemyController.knownDetectedTarget.transform.position);
              
m_EnemyController.TryAtack((m_EnemyController.knownDetectedTarget.transform.position - m_EnemyController.weapon.transform.position).normalized);
            break;
    }
}

Class: EnemyTurret

EnemyTurret has 2 AI states. Idle and Attack. It is too simple to analysis so I will skip it.

Class: Damageable

There is a Health class, which represent health of Player or Bot. To decrease player/bot health, there are two ways.

1.     Call TakeDamage method of health class.
2.     Through Damageable, call TakeDamage method of health class.

Number 2 used for projectiles. Number 1 used for player itself. (get damage by falling/environment or other reasons)


Add more feature

I will write it next article! 

Appendix

UnityAction
In this example uses UnityAction object. This is a delegate. If you haven’t heard about delegate, what about callback? Delegate has same idea like callback. Most different thing of delegate is it can call back many functions. Normally callback function is a single. Delegate we can register/add a callback functions like receiver/subscriber.


Final UML Diagram.
I noticed that this UML Diagram doesn't show everything of FPS microgame. When you are investigating/analyzing something, you don't need to look at everything. Concentrate on what you are looking/wanting. 



Friday, November 1, 2019

Time Calculator

I don't know why there is no program, which is able to set source time and based on the time difference calculate destination's time.

LA is -16 hours slower than South Korea. To make comfortable time for each others, I had to calculate -16 hours but as you know I'm a programmer and lazy.

So I created a program to calculate for me.




Source is really simple.

===================================

public partial class frmTimeCalculator : Form
{
    public frmTimeCalculator()
    {
        InitializeComponent();
    }


    private void frmTimeCalculator_Load(object sender, EventArgs e)
    {
        sourceTime.CustomFormat = "MM/dd/yyyy hh:mm:ss tt";
        sourceTime.Format = DateTimePickerFormat.Custom;

        destTime.CustomFormat = "MM/dd/yyyy hh:mm:ss tt";
        destTime.Format = DateTimePickerFormat.Custom;
    }

    private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
    {
        DateTime laTime = sourceTime.Value.AddHours(-16);
        destTime.Value = laTime;
    }
}

Task in UnrealEngine

 https://www.youtube.com/watch?v=1lBadANnJaw