SCharacter class overview - whoisEllie/Project-Isolation GitHub Wiki

SCharacter

Overview

SCharacter is the foundational class for project isolation. As the name suggests, this is the class which holds all the data and functions that the player will use to interact with the world. If we imagine all of project isolation as a flow chart, the SCharacter class is the centre of it all, with other classes (and indeed, mechanics implemented in these classes), branching out from SCharacter in various directions. This is where we implement the player's inputs, and potentially pass them through to other classes, such as the weapon.


Variables

  • FWeaponDataStruct - Contains the details for the currently spawned weapon, such as how much ammo it has, its health and its array of attachments.

  • USkeletalMeshComponent* meshComp; - meshComp is the mesh used for the player's hands. As SCharacter is built off of UE4's base Character class, it already comes with a mesh slot, which could in theory be used for a hands mesh. However, this slot is not set up to receive input from the mouse, and is best reserved for use with a full mesh in a third person setting. If you'd like to use a dual mesh system, it's recommended to use the Character mesh for the Third-person mesh, and to use meshComp for your First-person arms. Mesh can be adjusted in Blueprint.

  • UCameraComponent* cameraComp; - cameraComp is the component for the First-person camera. It's position and additional details are editable in Blueprint.

  • USpringArmComponent* springArmComp; - springArmComp is the RootComponent of the SCharacter class. It receives the input from the mouse that we need to rotate the camera. It's length is set to 0.0f in Blueprint, as we're using it for a First-person camera rather an a Third-person one. Details adjusted in Blueprints.

  • TSubclassOf<ASWeaponBase> primaryWeapon; - primaryWeapon keeps track of the player's, well, primary weapon. This variable needs to be updated if the player picks up a new weapon that you want to be 'permanent', i.e. stay in the player's inventory if they switch to another weapon, such as a pistol. If this variable is not updated, the player will be returned to their previous weapon when they hit '1', or whatever input you have set to call SwapToPrimary. Currently set in Blueprints.

  • TSubclassOf<ASWeaponBase> secondaryWeapon; - secondaryWeapon keeps track of the player's, well, secondary weapon. This variable needs to be updated if the player picks up a new weapon that you want to be 'permanent', i.e. stay in the player's inventory if they switch to another weapon, such as a rifle. If this variable is not updated, the player will be returned to their previous weapon when they hit '2', or whatever input you have set to call SwapToSecondary. Currently set in Blueprints.

  • ASWeaponBase* currentWeapon; - currentWeapon is a reference to the weapon the player is currently holding in their hands. It is used to call functions such as StartFire and Reload within the currently equipped weapon, and is updated with the UpdateWeapon function.

  • bool bWantsToAim - Keeps track of whether the player wants to aim or not. When we transition from states where the player is not allowed to aim to states where the player can aim, we can use this to let the player ADS without having to re-click the ADS button.

  • bool bIsAiming - Keeps track of whether the player is actually aiming or not

  • bool bHoldingCrouch - Keeps track of whether the player is holding the crouch button

  • bool bPerformedSlide; - Have we performed a slide yet?

  • bool bHoldingSprint; - Keeps track of whether the player is holding down the sprint button

  • bool isCrouching; - keeps track of whether we're crouching (for animations)

  • bool isSprinting; - keeps track of whether we're sprinting (for animations)

  • float finalCapsuleHalfHeight; - finalCapsuleHalfHeight is the target half-height for the capsule which the player will move to. Set in Blueprints.

  • float defaultCapsuleHalfHeight; - defaultCapsuleHalfHeight is the default height of the player. This is determined by the height of the CapsuleComponent in Blueprints, and set on EventContruct.

  • float crouchSpeed; - crouchSpeed is the speed at which the player should crouch (i.e. the interpolation speed between defaultCapsuleHalfHeight and finalCapsuleHalfHeight). Set in Blueprints.

  • float sprintSpeed; - sprintSpeed is the movement speed of the player while in the sprinting state. Set in Blueprints.

  • float walkSpeed; - walkSpeed is the movement speed of the player while in the walking state. Set in Blueprints.

  • float crouchMovementSpeed; - crouchMovementSpeed is the movement speed of the player while in the crouching state. Set in Blueprints.


Functions

  • void MoveForward(float value); - MoveForward is one of unreal's default functions, included with CharacterMovementComponent.h. We call it to allow the player to move forward/backwards (as value can be both positive and negative, with a negative value being backwards movement). UE4 documentation here)

  • void MoveRight(float value); - MoveRight is one of unreal's default functions, included with CharacterMovementComponent.h. We call it to allow the player to move right/left (as value can be both positive and negative, with a negative value being movement to the left). UE4 documentation here)

  • void LookUp(float value); - LookUp is one of unreal's default functions. We call it to pass through the respective mouse axis (Y in this case) as an input with which to move a component. In Project Isolation, we move a Spring Arm Component, as Cameras don't support receiving this type of input.

  • void LookRight(float value); - LookRight is one of unreal's default functions. We call it to pass through the respective mouse axis (X in this case) as an input with which to move a component. In Project Isolation, we move a Spring Arm Component, as Cameras don't support receiving this type of input.

  • void ExecCrouch(); - ExecCrouch is an alternative to UE4's built in Crouch function. Said crouch function is essentially a switch between two different capsule component heights, and as such instantly switches between a standing and a crouched state. ExecCrouch takes an alternative approach, where based on the player's current state, we either set the player to be crouched or standing. Following that, a chunk of code located in the Tick function switches a targetHalfHeight between the defaultCapsuleHalfHeight (or the half height of the player's capsule when the player is standing) and the finalCapsuleHalfHeight which is the half height of the capsule while the player is crouching. An FMath::FInterpTo function then smoothly transitions between the player's current capsule half height, and the desired value of targetHalfHeight.

  • void StartSprint(); - As we use two inputs for the sprinting implementation (An IE_Pressed and an IE_Released), we need to map this to two functions. StartSprint is called when the player presses down the chosen sprint key, and does exactly what it says on the tin, it puts the player into the sprinting state and updates any relevant variables.

  • void StopSprint(); - StopSprint is the opposite of StartSprint, and is called when the player releases the chosen sprint key. Note that it is only executed if the player stops sprinting by releasing the sprint key, not if the player crouches while they are sprinting. It does the same thing as StartSprint, but in reverse, putting the player into the walking state (if and only if the player is in the sprinting state at the time of execution) and updates any relevant variables.

  • void UpdateMovementSpeed(); - UpdateMovementSpeed exists in order to avoid cluttering functions such as StartSprint with numerous updates to the player's movement speed (GetCharacterMovement()->MaxWalkSpeed). It's called in ExecCrouch, StartSprint and StopSprint after they finish executing any required code, and updates the maximum movement speed based on the current movement state of the player. The movement speeds get updated based on the variables sprintSpeed, walkSpeed and crouchMovementSpeed, with each applying to their respective movement state.

  • void UpdateWeapon(TSubclassOf<ASWeaponBase> newWeapon); - UpdateWeapon is called every time we need to give the player a weapon. This does not assign a weapon to either the primary or secondary weapon slot, rather, it puts the weapon in the player's hands. The reference to this weapon is stored in the currentWeapon variable. The function takes a TSubClassOf<ASWeaponBase> as an input. It first destroys the current weapon the player has equipped, spawns the weapon that was passed through and then attaches it to the player character's skeletal mesh. Note that weapons will always be spawned regardless of collision overlaps, so make sure that any weapons you attempt to spawn have their collision response set to Ignore on all channels.

  • void SwapToPrimary(); - A function that exists because I don't know how to get UE to pass arguments through when using PlayerInputComponent->BindAction(). All it does is call UpdateWeapon(primaryWeapon)

  • void SwapToSecondary(); - A function that exists because I don't know how to get UE to pass arguments through when using PlayerInputComponent->BindAction(). All it does is call UpdateWeapon(secondaryWeapon)

  • void StartFire(); - StartFire passes the player's input through to the currentWeapon function of the same name.

  • void StopFire(); - StopFire passes the player's input through to the currentWeapon function of the same name.

  • void Reload(); - Reload passes the player's input through to the currentWeapon function of the same name.


Uses

The use for SCharacter is pretty clear - it's the foundation upon which we build our entire game. Within it, we handle all of our inputs, passing them through to various sub-classes, such as SWeaponBase. It also logically follows that this is where all of our movement and camera control code is stored and executed. If you wish to modify movement, I would recommend implementing your changes here. Anything else though, such as modifications to how weapons work, or any additional functionality such as a shield system akin to Halo should preferably be implemented in a separate actor and then attached to SCharacter.