Unreal Engine 4 C + + Platformergame custom role Controller source code analysis
The official store has a platformergame the entire free game, is a scroll class parkour game. The role controller of the whole project is very interesting, can run, jump, glide, cool. Here to analyze how it is implemented in detail.
Ucharactermovementcomponent This class implements most of the functions of the role controller, Platformergame implements a custom movmentcomponent, Called Uplatformerplayermovementcomp, which inherits from the standard Ucharactermovementcomponent and expands its behavior.
1. Constructors
UPlatformerPlayerMoveme Ntcomp::uplatformerplayermovementcomp (const class fpostconstructinitializeproperties& PCIP): Super (PCIP) { Maxacceleration = 200.0f; brakingdecelerationwalking = maxacceleration; Maxwalkspeed = 900.0f; Slidevelocityreduction = 30.0f; Slideheight = 60.0f; Slidemeshrelativelocationoffset = Fvector (0.0f, 0.0f, 34.0f); bwantsslidemeshrelativelocationoffset = true; Minslidespeed = 200.0f; Maxslidespeed = Maxwalkspeed + 200.0f; Modspeedobstaclehit = 0.0f; Modspeedledgegrab = 0.8f;}
Maxacceleration is the inherited variable, which represents the maximum acceleration of the role controller, Brakingdecelerationwalking, which is the effect of friction when the character is walking, the acceleration of the obstruction caused by it; Maxwalkspeed, The maximum speed of a character's walk; slidevelicityreduction, the amount of speed loss in a unit time when the character is coasting; slideheight, the height of the character controller when the character is taxiing, the altitude of the role control, and the collision, the glide, the character will be shorter, This can pass through some obstacles that cannot be passed by standing; Slidemeshrelativelocationoffset, this is the displacement of the control role glide, the model relative to the role controller; bwantsslidemeshrelativelocationoffset Whether a model of the displacement role is needed; minslidespeed, the character must initially have a speed before it can glide up, it is able to glide the minimum speed, below which the speed is not able to glide; maxslidespeed, the maximum speed the character can reach ; modspeedobstaclehit,modspeedledgegrab
2. Heavy-duty startfalling ()
void Uplatformerplayermovementcomp::startfalling (Int32 iterations, float remainingtime, float timetick, const fvector& Amp Delta, const fvector& subloc) {super::startfalling (iterations, Remainingtime, Timetick, Delta, Subloc); Movementmode = = move_falling && issliding ()) {trytoendslide ();}}
This method is inherited, and is called when the role switches from walking mode to falling mode. We assume that the character is taxiing, touches the front cliff, it starts to fall, the character must stop coasting, because it is about to start falling. The above code is the implementation of this function, when falling, if found currently in the slide, try to stop the glide.
3. Reload the scaleinputacceleration to move the character to the right
Fvector uplatformerplayermovementcomp::scaleinputacceleration (const fvector& inputacceleration) Const{FVector Newaccel = inputacceleration; aplatformergamemode* gi = Getworld ()->getauthgamemode<aplatformergamemode> (); if (GI && GI-> Isroundinprogress ()) {newaccel.x = 1.0f;} Return super::scaleinputacceleration (Newaccel);}
At the beginning of the game, the character will always start running to the right, and the player just needs to control the jump and glide at the right time. So how do you do it without typing, and keep running right? Always give the character an accelerated input. Here judging is not currently in the game process, is the words, always give the original inputacceleration parameter an x direction input. It's like you keep pressing the arrow keys.
4. Heavy-duty physwalking ()
void Uplatformerplayermovementcomp::P hyswalking (Float Deltatime, int32 iterations) {aplatformercharacter* MyPawn = Cast<aplatformercharacter> (Pawnowner); if (mypawn) {const BOOL bwantstoslide = Mypawn->wantstoslide (); if ( Issliding ()) {calccurrentslidevelocityreduction (deltatime); Calcslidevelocity (Velocity), const float CURRENTSPEEDSQ = velocity.sizesquared (); if (CURRENTSPEEDSQ <= Fmath:: Square (Minslidespeed)) {//slide have min speed-try to end Ittrytoendslide ();}} else if (bwantstoslide) {if (! Isflying () &&velocity.size () > Minslidespeed * 2.0f)//Make sure pawn have some velocity{startslide ();}} Super::P hyswalking (Deltatime, iterations);}
The physwalking is called whenever the walking state of the role needs to be updated. The invocation of this method will be more frequent. It updates the status of the current character's speed, glide, and so on, based on the character's input and current state. First, we read the character input bwantstoslide to see if we want to glide. If you are coasting, calccurrentslidevelocityreduction (deltatime) calculates the speed loss of the current role as a result of taxiing. Calcslidevelocity () to calculate the current speed of the slide. Then the current speed and the minimum speed can be compared, the speed loss to no longer glide, then stop the coasting state. The user has the input, said starts to glide, then examines, looks at the speed is not reached can glide the condition, then excludes is not in the flight, is not, then Startslide (), starts to glide.
5.CalcCurrentSlideVelocityReduction () calculates the speed loss of taxiing
void Uplatformerplayermovementcomp::calccurrentslidevelocityreduction (float deltatime) {float reductioncoef = 0.0f; const FLOAT floordotvelocity = fvector::D otproduct (CurrentFloor.HitResult.ImpactNormal, Velocity.safenormal ()); const BOOL Bneedsslopeadjustment = (floordotvelocity! = 0.0f); if (bneedsslopeadjustment) {const float Multiplier = 1.0f + F Math::abs<float> (floordotvelocity), if (Floordotvelocity > 0.0f) {reductioncoef + = Slidevelocityreduction * Multiplier; Increasing speed when sliding down a slope}else{reductioncoef-= slidevelocityreduction * Multiplier;//reducing speed When sliding up a slope}+}else{reductioncoef-= slidevelocityreduction;//reducing speed on flat ground}float Timedilati On = Getworld ()->getworldsettings ()->geteffectivetimedilation (); Currentslidevelocityreduction + = (REDUCTIONCOEF * timedilation * deltatime);}
First, the Currentfloor is what to do with the role in the walking mode, will always stand on a plane, this plane of data is described with Currentfloor.
const FLOAT floordotvelocity = fvector::D otproduct (CurrentFloor.HitResult.ImpactNormal, Velocity.safenormal ());
This line, in fact, is in the direction of the current velocity and the plane perpendicular to the angle of the cosine, vector point multiplication, it should not be difficult to understand. The degree of loss of speed when taxiing, and the angle between the ground and the current speed direction. You glide on the slope, the speed loss of more points, the slope down the line, the corresponding loss will be less. If two is vertical, it is said to be on a flat surface, then there is no need to adjust. Bneedsslopeadjustment, that's what it's for. Reductioncoef is the calculated velocity loss factor, which is then superimposed onto the currentslidevelocityreduction.
6.CalcSlideVelocity () Calculate glide speed
void Uplatformerplayermovementcomp::calcslidevelocity (fvector& outvelocity) const{const FVector VelocityDir = Velocity.safenormal (); Fvector newvelocity = Velocity + currentslidevelocityreduction * velocitydir;const float NEWSPEEDSQ = newvelocity.sizesqu Ared (); if (Newspeedsq > Fmath::square (maxslidespeed)) {newvelocity = Velocitydir * maxslidespeed;} else if (NEWSPEEDSQ < Fmath::square (minslidespeed)) {newvelocity = Velocitydir * minslidespeed;} outvelocity = newvelocity;}
It calculates the speed loss of the glide and is saved in the currentslidevelocityreduction. After the new speed is superimposed, the speed may be greater than the maximum speed, or it may not reach the minimum speed, which needs to be manipulated separately. Greater than, the new speed is the maximum glide speed, less than the new speed is the minimum glide speed.
7.StartSlide () Start sliding
void Uplatformerplayermovementcomp::startslide () {if (!binslide) {binslide = true; Currentslidevelocityreduction = 0.0f; Setslidecollisionheight (); aplatformercharacter* Myowner = cast<aplatformercharacter> (Pawnowner); if (Myowner) {MyOwner-> Playslidestarted ();}}}
Start some variables, set the collision height of the character, and then notify character to play the animation that starts to glide, and so on.
void Uplatformerplayermovementcomp::trytoendslide () {//End slide If collisions allowif (binslide) {if ( Restorecollisionheightafterslide ()) {binslide = false; aplatformercharacter* Myowner = cast<aplatformercharacter> (Pawnowner); if (Myowner) {MyOwner-> Playslidefinished ();}}}
This method tries to end the coasting state, needs to restore the previous collision height, and then notifies the character to play the sliding end animation.
8.SetSlideCollisionHeight () and Restorecollisionheightafterslide ()
void Uplatformerplayermovementcomp::setslidecollisionheight () {if (! Characterowner | | Slideheight <= 0.0f) {return;} Do not perform if collision are already at desired size.if (Characterowner->capsulecomponent->getunscaledcapsuleh Alfheight () = = Slideheight) {return;} Change collision size to new Valuecharacterowner->capsulecomponent->setcapsulesize (characterowner-> Capsulecomponent->getunscaledcapsuleradius (), slideheight);//applying correction to Pawnowner mesh relative Locationif (bwantsslidemeshrelativelocationoffset) {acharacter* defcharacter = Characterowner->getclass () Getdefaultobject<acharacter> (); const Fvector Correction = defcharacter->mesh->relativelocation + Slidemeshrelativelocationoffset; Characterowner->mesh->setrelativelocation (Correction);}}
This method modifies the collision height, and then adjusts the offset of the model as needed.
BOOL Uplatformerplayermovementcomp::restorecollisionheightafterslide () {acharacter* Characterowner = Cast< Acharacter> (Pawnowner); if (! Characterowner) {return false;} acharacter* defcharacter = Characterowner->getclass ()->getdefaultobject<acharacter> (); const FLOAT Defhalfheight = Defcharacter->capsulecomponent->getunscaledcapsulehalfheight (); const float DefRadius = Defcharacter->capsulecomponent->getunscaledcapsuleradius ();//Do not perform if collision are already at desired Size.if (characterowner->capsulecomponent->getunscaledcapsulehalfheight () = = DefHalfHeight) {return true;} const FLOAT Heightadjust = Defhalfheight-characterowner->capsulecomponent->getunscaledcapsulehalfheight (); Const Fvector newlocation = characterowner->getactorlocation () + fvector (0.0f, 0.0f, heightadjust);//Check if there is Enough space for default capsule sizefcollisionqueryparams traceparams (TEXT ("Finishslide"), false, Characterowner); Fcollisionresponseparams ResponSeparam;initcollisionparams (Traceparams, responseparam); const BOOL bblocked = Getworld ()->overlaptest ( NewLocation, Fquat::identity, Updatedcomponent->getcollisionobjecttype (), Fcollisionshape::makecapsule ( Defradius, Defhalfheight), traceparams); if (bblocked) {return false;} Restore capsule size and move up to adjusted Locationcharacterowner->teleportto (NewLocation, characterowner-> Getactorrotation (), false, true); Characterowner->capsulecomponent->setcapsulesize (Defradius, defhalfheight);//Restoring original PawnOwner Mesh relative locationif (bwantsslidemeshrelativelocationoffset) {characterowner->mesh->setrelativelocation ( defcharacter->mesh->relativelocation);} return true;}
When restoring the collision height, it is necessary to test whether the current can be restored, such as an obstacle on top of the head, is not able to recover.
const BOOL bblocked = Getworld ()->overlaptest (NewLocation, fquat::identity, updatedcomponent-> Getcollisionobjecttype (), Fcollisionshape::makecapsule (Defradius, defhalfheight), traceparams);
In this line, test the location where you want to restore the collision, see if there is anything to overwrite, and transfer the character to this location. Finally, the offset of the role model is restored.
9. Handling of obstacles and gripping edges encountered
void Uplatformerplayermovementcomp::P ausemovementforobstaclehit () {savedspeed = Velocity.size () * Modspeedobstaclehit; stopmovementimmediately ();D isablemovement (); Trytoendslide (); }void Uplatformerplayermovementcomp::P ausemovementforledgegrab () {savedspeed = Velocity.size () * MODSPEEDLEDGEGRAB; stopmovementimmediately ();D isablemovement (); Trytoendslide ();}
Pausemovementforobstaclehit () Handles situations when an obstacle is encountered. Pausemovementforledgegrab () handles the situation when the edge of the barrier is fetched. is to save the current speed, then stop moving and stop coasting.
10.RestoreMovement () Resume Mobile
void Uplatformerplayermovementcomp::restoremovement () {setmovementmode (move_walking); if (Savedspeed > 0) { Velocity = Pawnowner->getactorrotation (). Vector () * savedspeed;}}
Gives the saved speed value in the direction that the current character is facing.
Unreal Engine 4 C + + Platformergame custom role Controller source code analysis