Thursday, October 31, 2019

Unity : FPS Microgame Analysis -1-

Unity released very good FPS example for people and I decided to analysis how they make this. Personally I wanted to show you how I analysis the games.

Class: Player Input Handler


What Player Input Handler class does is controlling a player. It reference to GameFlowManager and get the state of current game to ignore user input when game is finished.

To Change Weapon
If user press 1, 2, 3 and so on, we can get positive number and it is used in PlayerWeaponsManager class.

Class: Player Character Controller

PlayerCharacterController class controls player’s character. Many properties are adjustable to game feel better. It uses PlayerWeaponsManager to change weapon and Health Class. Health Class is managing health for player and bots.(Both uses Health Class)

Class: PlayerWeaponsManager

At the beginning of the game player should have weapon. Variable ‘startingWeapons’ contains initial weapon list.

Weapon camera
Weapon has its own camera to render the weapon on top of main camera. Default position of weapon uses DefaultWeaponPosition. When User Press zoom (which is aiming), it will use AimingWeaponPosition. Its x value is 0 which means aligned to 0 of x.

Aiming
When user press right button, Aiming is activated. As soon as aiming is activated then all of camera’s FOV(field of view) is changed. This effect will make zoom in. FOV Animation is code driven which means changing FOV value is running by code.

void UpdateWeaponAiming()
{
    if (m_WeaponSwitchState == WeaponSwitchState.Up)
    {
        WeaponController activeWeapon = GetActiveWeapon();
        if (isAiming && activeWeapon)
        {
            m_WeaponMainLocalPosition = Vector3.Lerp(m_WeaponMainLocalPosition, aimingWeaponPosition.localPosition + activeWeapon.aimOffset, aimingAnimationSpeed * Time.deltaTime);

            SetFOV(Mathf.Lerp(m_PlayerCharacterController.playerCamera.fieldOfView, activeWeapon.aimZoomRatio * defaultFOV, aimingAnimationSpeed * Time.deltaTime));
        }
        else
        {
            m_WeaponMainLocalPosition = Vector3.Lerp(m_WeaponMainLocalPosition, defaultWeaponPosition.localPosition, aimingAnimationSpeed * Time.deltaTime);
            SetFOV(Mathf.Lerp(m_PlayerCharacterController.playerCamera.fieldOfView, defaultFOV, aimingAnimationSpeed * Time.deltaTime));
        }
    }
}
In here, we use aimingWeaponPosition and defaultWeaponPosition.


To display crosshair hud
At the end of update function, raycast and set the isPointingAtEnemy bool variable. This variable is used by CrosshairManager which will display crosshair hud based on isPointingAtEnemy.

<Raycast fail and no enemy>

<Raycast success then CrosshairManager will show different hud>

Weapon Change Animation
When user change the weapon, current weapon position moves down and changed 3d model (actually hide current weapon and show new weapon) and then move up. In this case, we use DownWeaponPosition.


 

Class: Jetpack

After user unlock Jetpack, user press spacebar then player can fly. A relationship between PlayerCharacterController and Jetpack is like down below.


Player’s movement uses characterVelocity. In every update frame of Jetpack checks and applying additional velocity into characterVelocity.

<<Gameplay Idea: Implement a skill ‘Relentless Pursuit’ of Lucian in LOL or Tracer’s Blink>>

Class: Actor


When Actor is activated, we register itself to ActorsManager actors container. ActorsManager doesn’t have any other logic. Actor also has no logic at all but it has aimPoint variable. This variable is for aiming. For instance bot is targeting a player then bot should have specific target. The target will use aimPoint of Actor class.

Class: WeaponController

Every weapon objects has WeaponController component. WeaponController represent weapon itself. Weapon type, decide which projectile should use, bulletSpreadAngle (for shotgun), aimZoomRatio and so on.

Zoom for sniper
For instance, we have sniper rifle then we probably has zooming function more than pistol. In that case, we can use aimZoomRatio. If we set animZoomRatio to be 0.3 for instance, then zoom is way bigger than 0.7

<aimZoomRatio 0.7>

<aimZoomRatio 0.3>

Firing
In WeaponController, we instantiate projectile prefabs. Function flow like down below.

HandleShootInputs -> TryShoot -> HandleShoot

Bullet position
Every generated bullets position set by weaponMuzzle. In addition, muzzle flash effect is generated.

Prevent firing too quickly
If we call HandleShoot function really quickly, bullets will be generated. If we call HandleShoot every single time when user press the button then bullets will be generated really quickly if user has lighting speed hand! We have to prevent it. There is a variable m_LastTimeShoot which will prevent calling a function really quickly. This is timing logic.


Class: EnemyController


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)



That is it for today. Next time I'll look how projectile works (probably collision detection), add more features such as spawner for bot, user's new skills (tracer blink!)





1 comment:

  1. Hi, that's very interesting, thanks! I was wandering if it was possibile to make the input for mobile... I can't get out of this problem, could you help me some how?

    ReplyDelete

Task in UnrealEngine

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