Announcement

Collapse
No announcement yet.

[VIDEO][CODE] Multiplayer Replication P3, GrappleHook: Custom Pawn Movement Mechanics

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    [VIDEO][CODE] Multiplayer Replication P3, GrappleHook: Custom Pawn Movement Mechanics

    Dear Community,

    Replication Series
    Part 1: Change Pawn Materials Based On a Unique PlayerID
    Part 2: Efficiently Replicate Custom Special Effects & Projectile Bounces
    Part 3: Grapple Hook and Custom Pawn Movements
    Part 4: Listen Servers - Replicating Special Effects


    In this tutorial I show you how you can replicate your own custom pawn movement mechanics!

    I am showing you how you can create your own truly unique player movement mechanics for your multiplayer game!

    In this example I am extending a previous tutorial on how to create a tether/grapple hook system for skeletal mesh pawns.

    Video Tutorial: Grapple Hook / Tether System for Skeletal Mesh Pawns, Complete Code and Grapple Beam Effect For You

    I modified the code in tutorial above to create a multiplayer version of this custom player movement mechanic!

    As you can see from the video, the changes to the pawn's movement are:

    1. player controlled, meaning the pawn movements cannot simply be predicted, but this allows for a truly new game mechanic to be replicated in unreal multiplayer games.

    2. quite dramatic, enabling movement patterns not possible with standard jump or dodge pawn functions




    ~~~

    Code For You

    Below is the entire code I am using for the tether movements of the player pawns that you see in my video !

    I took out all the code about the tether effect because all those effects are run clientside

    The purpose of this tutorial is to show you how you can easily create custom player movement systems,

    and below is the entire code for the very unusual player movements you see replicated in the video.

    Code:
    //pawn class
    
    var float deltaTimeBoostMultiplier;
    
    //play regular animations or only skeletal controller?
    var bool SkeletalControllerOnly;
    var bool TetheringAnimOnly;
    
    //=======================
    // Tether System
    //=======================
    var actor 					curTargetWall;
    var vector 					wallHitLoc;
    var ParticleSystemComponent tetherBeam;
    var float 					tetherMaxLength;
    var float					tetherlength;
    var float 					tetherNetBoost;
    var vector 					prevTetherSourcePos;
    
    var Rotator r;
    var vector vc;
    var vector vc2;
    
    //repnotified for clientside tether effects
    var repnotify bool isTethering;
    
    simulated function PostBeginPlay() {
    	
    	//very important line
    	super.PostBeginPlay();
    	
    	//NET MODE SPECIFIC
    	if(worldinfo.netmode == NM_Standalone){
    		tetherNetBoost = 1;
    	}
    	else {
    		tetherNetBoost = 3;
    	}
    }
    
    //called from controller class
    reliable server function increaseTether() {
    
    	if (tetherlength > tetherMaxLength) return;
    	tetherlength += 20;
    }
    
    //called from controller class
    reliable server function decreaseTether() {
    	
    	if (tetherlength <= 0) {
    		tetherlength = 0;
    		return;
    	}
    	tetherlength -= 20;
    }
    
    //called from controller class
    reliable server function detachTether() {
    	
    	curTargetWall = none;
    	
    	//change pawn physics
    	SetPhysics(PHYS_Walking);
    	isTethering = false;
    	TetheringAnimOnly = false;
    }
    
    //called from controller class
    reliable server function createTether(rotator playerRot) {
    	local vector hitLoc;
    	local vector hitNormal;
    	local actor wall;
    	
    	//~~~ Trace ~~~
    	vc = getPowerStartLocation();
    	
    	
    	//trace from VictoryUnit
    	vc2 = Vector(playerRot);
    	vc += 60 * vc2; 
    	
    	//trace to see if ball still close to most recent surface
    	//trace only to tether's max length
    	wall = Self.trace(hitLoc, hitNormal, 
    					vc + tetherMaxLength * vc2, 
    					vc
    			);
    			
    	if(Wall == none) return;
    	
    	//~~~~~~~~~~~~~~~
    	// Tether Success
    	//~~~~~~~~~~~~~~~
    	
    	//state
    	isTethering = true;
    	
    	curTargetWall = Wall;
    	wallHitLoc = hitLoc;
    	
    	//get length of tether from starting
    	//position of object and wall
    	tetherlength = vsize(hitLoc - Location);
    }
    
    //called every tick that istethering is true
    //on the server
    reliable server function tetherCalcs() {
    	
    	//~~~~~~~~~~~~~~~~~~~~~~~~
    	//Actual Tether Constraint
    	//~~~~~~~~~~~~~~~~~~~~~~~~
    	
    	//vector between player and tether loc
    	vc = Location - curTargetWall.Location;
    	
    	if (Vsize(vc) > tetherlength) {
    		TetheringAnimOnly = true;
    		SetPhysics(PHYS_Falling);
    		
    		vc2 = normal(vc);
    		//pc.optimize("velocity diff"@abs(vsize(Normal(velocity) - vc2)));
    		
    		//moving in same direction as tether?
    		if(abs(vsize(Normal(velocity) - vc2)) > 1){
    		
    		//limit max velocity applied to pawn in direction of tether
    		if(vsize(velocity) < 3000 * deltaTimeBoostMultiplier){
    			velocity -= vc2 * 120 * tetherNetBoost;
    		}
    		}
    		
    		//not moving in direction of pawn
    		//apply as much velocity as needed to prevent falling
    		//allows sudden direction changes
    		else {
    			velocity -= vc2 * 120 * tetherNetBoost;
    		}
    	}
    	else {
    		//only stop regular anims when changing pawn velocity
    		TetheringAnimOnly = false;
    	}
    }
    Simulated Event Tick(float DeltaTime)
    {
    	Super.Tick(DeltaTime);
    
    	//for fps issues and keeping things properly up to date
    	deltaTimeBoostMultiplier = deltatime * 40;
    
    	
    	//=== TETHER ====
    	if (isTethering) {
    		tetherCalcs();
    	}
    }
    Things to Note

    -All functions that are affecting the pawn's movement are being run on the SERVER, not the client.

    -All the server functions are reliable because they must occur in right order so that the pawn's
    position is same for all clients regardless of individual connection speeds

    -tetherNetboost is used because vectors get compressed across network and so the end result is that the server needs to run with a higher velocity value, or else the compressed vector needs to be reexpanded later.

    ~~~

    Why Running Player Movement Changes on Server?

    The player can use WASD to affect the tether movements so instead of simulated I need to have the server update the pawn position on all client machines.

    Additionally, the way unreal engine handles pawn movement can be quite intricate, to get an idea of it look at:

    //playercontroller.uc
    Code:
    unreliable server function ServerMove(float TimeStamp, vector InAccel, vector ClientLoc, byte MoveFlags, byte ClientRoll, int View)
    
    function ServerMoveHandleClientError(float TimeStamp, vector Accel, vector ClientLoc)
    
    SendClientAdjustment();
    
    unreliable client function LongClientAdjustPosition
    (
    	float TimeStamp,
    	name newState,
    	EPhysics newPhysics,
    	float NewLocX,
    	float NewLocY,
    	float NewLocZ,
    	float NewVelX,
    	float NewVelY,
    	float NewVelZ,
    	Actor NewBase,
    	float NewFloorX,
    	float NewFloorY,
    	float NewFloorZ
    )
    To avoid getting into all this complexity in order to create custom player pawn movements I chose to just update the pawn's velocity on the server.

    It is not efficient to run a lot of code on the server however, so please note that all the tether special effects you see in video are running clientside, in the above code are the only server funcs, which are server funcs because it would be very hard to predict player input regarding the tether system.

    ~~~

    Good Network Coding Policy

    Run As Much Client-side As You Can

    It is very good practice to run as much code as you can clientside !

    The reason that the tether visual effects replicate so nicely in the video is because all tether effects, even for other players, are actuall run client side.

    ~~~

    Tether Effect Overview

    Basically I only replicate a single state change, determining whether or not the player is tethering or not using bool istethering.

    Because this variable is repnotified, it will be updated for all players' machines, in addition to the player who is doing the tethering.

    Because the actual visual game mechanic of tethering is simple, just drawing a beam from the player to the tether location, I can run the entire effect client side because the pawn's position is getting updated properly on the server via the code above.

    This means that the pawn's position for all player machines is already up to date, and I can just draw the effect clientside!

    I did not include all the tether effect code because it would complicate my focus for this tutorial

    ~~~

    Summary

    Using the code above as a guide, as well as referring to my earlier tether tutorial, you can see exactly how I created a custom pawn movement game mechanic that is able to work correctly in multiplayer !



    Rama

    #2
    Thanks for the video. That's very interesting and might be helpful for me someday.

    Comment


      #3
      I posted a better higher resolution you tube video where you can see the pawn movements much more clearly!

      Enjoy!



      Rama

      Comment


        #4
        Awesome Rama

        Comment


          #5
          Nice to hear from you Ryanjon!

          @quanganht : you're welcome!



          Rama

          Comment

          Working...
          X