Announcement

Collapse
No announcement yet.

[CODE] Rama's Physics-Based Retractable Tether / Grapple Hook for Skeletal Mesh Pawns

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

    [CODE] Rama's Physics-Based Retractable Tether / Grapple Hook for Skeletal Mesh Pawns

    Move pawns around as if with RB_Constraints and Rigid Body Physics

    Dear Community,

    Here I present to you a fully functional physics tether system for skeletal mesh actors!

    See the Video Demoing the Complete Code I am providing you with below!

    ~~~

    Code-Required Art Asset Package File Download

    I give you the Art Asset I use in the video of the Tether Beam Effect for use with my complete code sample!

    Rama Tether Beam Package - Download Tether Beam Art Asset UPK File (Nov 2012 UDK Build)




    This code is:

    -low level simple functions for unreal engine to handle

    -optimized for variable memory access, I use multiple-purpose global variables to minimize creation/destruction of variables, and to enable the actual tether functionality to be optimized

    -easy on replication, as I am not using any custom animations or Rigid Body / ragdoll states

    -still looks really good and is easy to control in-game to make for awesome fun gameplay

    -works regardless of framerate, see the DeltaTimeBoostMultiplier for details, even if frame rate fluctuates the beam is kept in same location as the pawn's skeletal mesh socket.

    -This is all my own original code after many hours, weeks of my own efforts over time, I wrote it all from scratch (the code here took me only a few hours to write, but the learning that went into this happened over several weeks.


    ~~~

    Entire Code For You

    I am providing you with the entire code and art asset I created myself from scratch to:

    1. create a tether beam and control its start point and end point, so that the beam can be attached to a hand or weapon socket in 3rd person viewing. (or first person)

    2. enable this tether beam to have its length dynamically adjusted during game time, after it has been created, so as to move the pawn around if tether is retracted, lifting pawn into air, or setting pawn back on the gorund

    3. release and restart the tether beam any time, including in mid air so as to swing from platform to platform.

    4. Smoothly and easily go from running/jumping/shooting attacking to using tether and then back again! It's instantaneous! Great for gameplay

    5. the Player can still control the pawn using regular WASD keys while it moves around in the air due to tether, which is great for gameplay to control where player will land. It's a lot of fun!

    How to Turn Off All Pawn Animations Via UnrealScript
    and Replace with Animation of Choice

    6. I show you how to turn off all standard UT Pawn animations, or turn them back on, through a single unrealscript variable, and then set an alternative animation to play while rest of UT animations are turned off.


    This is what makes the pawn look very natural with tether in the video!

    ~~~

    Special Features Of This Code

    I found a way to do everything I am saying above WITHOUT forcing the pawn into PHYS_RigidBody, but it still looks awesome in game! See video!

    This code is very light weight on the cpu and unreal engine, and would be easy to replicate in multiplayer games since no fancy physics is even being utilized.

    Everything is done with modifications to the player velocity, but in a way that is simple and yet very flowing.


    ~~~

    Key Bindings

    To utilize my code you will need to set some custom key bindings to activate the tether and changes its size. See my other tutorials for more info on this.

    ~~~

    No RB_Constraint

    In my earlier tutorials for tethers with Kactors I used an RB_Constraint to create the tether effect.

    In this version there is not even an RB_Constraint!

    I control the entire tether effect with low-level and simple code.

    See my code and the video for details

    ~~~

    Essential Tether Art Asset For You (Download)

    One of the more complicated parts of this endeavor was actually the tether beam.

    Getting the tether beam to work properly in THIRD person was a bit of a challenge because the tether needs to have its source point attached to a skeletal mesh socket, and update its starting position to match the world position of the skeletal mesh socket.

    Since this was rather complicated I am simply providing you with this art asset for your own use with this code

    Enjoooy

    ~~~~~~~
    Download
    ~~~~~~~

    Rama Tether Beam Package

    Please note this art asset was made with Nov 2012 UDK,

    so if you have an earlier version, you will have to construct some of the harder parts of the art asset yourself, namely creating a vector paramater for the source points of all the beam components.

    You can use: ParticleSystem'WP_LinkGun.Effects.P_WP_Linkgun_Alt beam_Red'

    as a starting point

    You will need to

    1. set the source of the beam to use vector parameter and name it to match the unrealcode
    2. set the source beam to ABSOLUTE (so it uses absolute world coordinates not local to emmiter)
    3. Change the name of the target parameter to match my tutorial code
    4. delete the core beams that are more whitish, they dont work right when source point is set to vector parameter


    ~~~
    Entire Core Code For You
    ~~~

    Controller Class

    //In your Controller class you will need to call
    Code:
    CreateTether()
    DetachTether()
    increaseTether()
    decreaseTether()
    with various key presses that you bind to keys, see my other tutorials for more info on keybinding

    You will also need this variable in your Controller class

    Code:
    var bool isTethering;

    In my code I use the G key, and on keydownG() I create tether, and onRelease I detach tether

    ~~~

    My Increase / Decrease Tether Works Every Tick

    I use the up arrow and down arrow on keyboard to change the length of the tether EVERY TICK

    So please note in your implementation that IncreaseTether and Decrease Tether expect to be called every tick that the relevant key is being held down.

    ~~~

    Reference to Controller Class, “PC” in my code

    In your pawn class, where most of this code is, you will need a reference to the controller class.

    In my case “pc” is the reference to the controller class.

    For more info on how to connect your pawn to its controller using a reference var you create during PostBeginPlay, see this tutorial of mine, about 1/3 of the way down.

    Here's the important image, see tutorial for more info about this image



    ~~~

    Main Code - Pawn Class

    All the rest of the code is in your pawn class!

    Global vars

    Code:
    //=============================================
    // Tether System
    //=============================================
    var actor 				curTargetWall;
    var vector 				wallHitLoc;
    var ParticleSystemComponent 				tetherBeam;
    var float 				tetherMaxLength;
    var float				tetherlength;
    var vector 				prevTetherSourcePos;
    
    //these are optimization vars
    //their values should never be relied on
    //used to reduce variable memory allocation/deallocation
    //this improves algorithm speed dramatically in my experience
    var rotator r;
    var vector vc;
    var vector vc2;
    Core Functions below, again this is all in Pawn Class

    I am extending from UTPAWN, but you could adapt this code to anything

    as long as your pawn has a skeletalmeshcomponent named “mesh”

    or change “mesh” to be your pawn's skeletal Mesh component.


    Code:
    //=============================================
    //  Rama Tether System
    //
    //This code was obtained from this page
    //
    //http://forums.epicgames.com/threads/964242-CODE-Rama-s-Physics-Based-Retractable-Tether-Grapple-Hook-for-Skeletal-Mesh-Pawns
    //
    //=============================================
    function increaseTether() {
    
    	if (tetherlength > tetherMaxLength) return;
    	tetherlength += 20;
    }
    function decreaseTether() {
    	
    	if (tetherlength <= 384) {
    		tetherlength = 384;
    		return;
    	}
    	tetherlength -= 20;
    }
    
    function detachTether() {
    	
    	curTargetWall = none;
    	
    	//beam
    	if(tetherBeam != none){
    		tetherBeam.SetHidden(true);
    		tetherBeam.DeactivateSystem();
    		tetherBeam = none;
    	}
    	
    	
    	SetPhysics(PHYS_Walking);
    
            //state
    	pc.isTethering = false;
    
    	//make sure to restore normal pawn animation playing
    	//see last section of tutorial
    	TetheringAnimOnly = false;
    }
    
    function createTether() {
    	local vector hitLoc;
    	local vector hitNormal;
    	local actor wall;
    	local vector startTraceLoc;
    	//~~~ Trace ~~~
    	
    	vc = Vector(pc.Rotation);
    	
    	//pawn location + 100 in direction of player camera
    	startTraceLoc = Location + vc * 100;
    	
    	//trace only to tether's max length
    	wall = Self.trace(hitLoc, hitNormal, 
    				startTraceLoc + tetherMaxLength * vc, 
    				startTraceLoc
    			);
    	
    	if(!Wall.isa('Actor')) return;
    	
    	//~~~~~~~~~~~~~~~
    	// Tether Success
    	//~~~~~~~~~~~~~~~
    	//Clear any old tether
    	detachTether();
    	
    	//state
    	pc.isTethering = true;
    	
    	curTargetWall = Wall;
    	wallHitLoc = hitLoc;
    	
    	//get length of tether from starting
    	//position of object and wall
    	tetherlength = vsize(hitLoc - Location);
    	//~~~
    	
    	//~~~ Beam UPK Asset Download ~~~ 
    	//I provide you with the beam resource to use here:
    	//requires Nov 2012 UDK
    	//Rama Tether Beam Package [Download] For You
    	tetherBeam = WorldInfo.MyEmitterPool.SpawnEmitter(
    
    		//change name to match your imported version 
    		//of my package download above
    		//In UDK: select asset and right click “copy full path”
    		//paste below
    		ParticleSystem'ramaPackage3.ParticleSystem.TetherBeam', 
    		Location + vect(0, 0, 32) + vc * 48, 
    		rotator(HitNormal));
    
    	tetherBeam.SetHidden(false);
    	tetherBeam.ActivateSystem(true);
    	
    	//Beam Source Point
    	Mesh.GetSocketWorldLocationAndRotation('DualWeaponPoint', vc, r);
    	tetherBeam.SetVectorParameter('TetherSource', vc);
    	
    	//Beam End
    	tetherBeam.SetVectorParameter('TetherEnd', hitLoc);	
    }
    
    //these calcs run every tick while tether is active
    //so the code is optimized to reduce
    //variable memory allocation and deallocation
    //I use global vars vc and vc2 as variables to store different
    //info I need for my tether algorithm
    
    //the other vars are also global since they are assigned values
    //in other tether functions
    //and their values should NOT be recalculated every tick
    
    //~~~~~~~~~~~~~~~~~~~~~~~~~~
    //Rama's Tether System Calcs
    //~~~~~~~~~~~~~~~~~~~~~~~~~~
    function tetherCalcs() {
    	
    	//~~~~~~~~~~~~~~~~~
    	//Beam Source Point
    	//~~~~~~~~~~~~~~~~~
    	//get position of source point on skeletal mesh
    
    	//set this to be any socket you want or create your own socket
    	//using skeletal mesh editor in UDK
    
    	//dual weapon point is left hand 
    	Mesh.GetSocketWorldLocationAndRotation('DualWeaponPoint', vc, r);
    	
    	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    	//adjust for Skeletal Mesh Socket Rendered/Actual Location tick delay
    
    	//there is a tick delay between the actual socket position
    	//and the rendered socket position
    	//I encountered this issue when working skeletal controllers
    	//my solution is to just manually adjust the actual socket position
    	//to match the screen rendered position
    	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    	//if falling, lower tether source faster
    	if (vc.z - prevTetherSourcePos.z < 0) {
    		vc.z -= 8 * deltaTimeBoostMultiplier;
    	}
    	
    	//raising up, raise tether beam faster
    	else {
    		vc.z += 8 * deltaTimeBoostMultiplier;
    	}
    	
    	//deltaTimeBoostMultipler neutralizes effects of 
    	//fluctuating frame rate / time dilation
    
    	//update beam based on on skeletal mesh socket
    	tetherBeam.SetVectorParameter('TetherSource', vc);
    	
    	//save prev tick pos to see change in position
    	prevTetherSourcePos = vc;
    	
    	
    	//~~~~~~~~~~~~~~~~~~~
    	//Actual Tether Constraint
    
    	//I dont use a RB_Constraint
    	//I control the allowed position
    	//of the pawn through code
    	//and use velocity adjustments every tick
    	//to make it look fluid
    
    	//setting PHYS_Falling + velocity adjustments every tick 
    	//is what makes this work
    	//and look really good with in-game physics
    	//~~~~~~~~~~~~~~~~~~~
    	
    	//vector between player and tether loc
    	//curTargetWall was given its value in createTether()
    	vc = Location - curTargetWall.Location;
    	
    	//dist between pawn and tether location
    	//see Vsize(vc) below (got rid of unnecessary var)
    	
    	
            //is the pawn moving beyond allowed current tether length?
            //if so apply corrective force to push pawn back within range
    	if (Vsize(vc) > tetherlength) {
    		
                    //determine whether to remove all standard pawn
    	        //animations and just use the Victory animation
    	        //I use this to make animations look smooth while my Tether System
                    //is applying changes to pawn velocity (otherwise strange anims play)
    
                    //this also results in pawn looking like it is actively initiating the
                    //change in velocity through some Willful Action
                    TetheringAnimOnly = true;
    		
                    SetPhysics(PHYS_Falling);
    		
    		//direction of tether = normal of distance between
    		//pawn and tether attach point
    		vc2 = normal(vc);
    		
    		//moving in same direction as tether?
    
    		//absolute value of size difference between
    		//normalized velocity and tether direction
    		//if > 1 it means pawn is moving in same direction as tether
    		if(abs(vsize(Normal(velocity) - vc2)) > 1){
    		
    		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    		//limit max velocity applied to pawn in direction of tether
    		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    		//50 controls how much the pawn moves around while attached to tether
    		//could turn into a variable and control for greater refinement of
    		//this game mechanic
    
    		//1200 is the max velocity the tether system is allowed to force the
    		//pawn to move at, adjust to your preferences
    		//could also be made into a variable
    		if(vsize(velocity) < 1200){
    			velocity -= vc2 * 50;
    		}
    		}
    		
    		//not moving in direction of pawn
    		//apply as much velocity as needed to prevent falling
    		//allows sudden direction changes
    		else {
    			velocity -= vc2 * 50;
    		}
    	}
    	else {
    		//allow all regular ut pawn animations
                    //since player velocity is not being actively changed 
                    //by Rama Tether System
                    TetheringAnimOnly = false;
    	}
    	/*
    	//if the target point of tether is attached to moving object
    
    	if (tetheredToMovingWall) {
    		//beam end point
    		tetherBeam.SetVectorParameter('TetherEnd', 					
    		curTargetWall.Location);
    	}
    	*/
    }
    Simulated Event Tick(float DeltaTime)
    {
       	 Super.Tick(DeltaTime);
    	
    	//for fps issues and keeping things properly up to date
    	//specially for skeletal controllers
    
    	deltaTimeBoostMultiplier = deltatime * 40;
    	
    	//the value of 40 was acquired through my own hard work and testing,
    	//this deltaTimeBoostMultiplier system is my own idea :)
    
    	//=== TETHER ====
    	//pc is ref to controller class
    	if (pc.isTethering) {
    		tetherCalcs();		//run calcs every tick tether is active
    	}
    }
    defaultproperties
    { 
    	//tether
    	tetherMaxLength = 4000
    }
    ~~~

    Removing All Pawn Animations While Tether is Adjusting Player Velocity
    Play Animation of Your Choice Instead


    Stop All UT Pawn Anims and Play Custom Anim Via a Single UnrealScript Boolean Value Set Dynamically and Repeatedly During Game Time

    I used a special AnimTree node and a unrealscript variable to turn off all standard pawn animations when the tether is actively adjusting pawn velocity.

    This is what makes the whole thing look really good in my video!




    This is a modified version of the standard UT AnimTree for Pawns.

    Notice how there are two nodes added before entire UT Animation tree of nodes is connected to the core node.

    This means that these two nodes of mine control whether or not the core node receives any anim info at all.

    And in the case of skeletal controllers only, no alternate animation is provided.

    But for tethering, I provide the Victory animation, standard UT pawn animation from

    AnimSet'CH_AnimHuman.Anims.K_AnimHuman_BaseMale'

    The Blend by Property node checks the value of variables stored in the class of the actor who owns the skeletal mesh component that has this anim tree.

    So this means that if you want to control animations via unrealscript you need to put those variables in the pawn class who owns the skeletal mesh, not in a controller class or worldinfo.

    The Blend by Property Node ONLY checks variables on the pawn who has the skeletal mesh

    The only exception is if you tell the Blend by Property to check the class instance that the Actor with this animtree is based on. (such as a hoverboard for ex)

    In this case, the property / variable is:

    TetheringAnimOnly

    So you put this value into your own Blend By Property Node on your own AnimTree for your pawn.

    Then you add inputs and name them, you only want 2.

    Right-click on node input points themselves to rename inputs
    Right-click on node to add/delete inputs


    Because the unrealscript var is a boolean value, there should only be two inputs.

    Input 0 runs when boolean is false
    Input 1 runs when boolean is true

    So this means that “Normal” which allows all UT animations to pass in and play, will only run if in the unrealscript code TetheringAnimOnly == false at any moment of game time.

    Whenever TetheringAnimOnly is set to true during game time, the Blend By Property node runs the Input 1, which is the victory animation, and nothing else at all!

    Here's more info on how you can use Blend By Property for up to 255 different game states.

    UDN Blend By Property Reference, Control Pawn Animations for Up To 255 Different States

    ~~~

    Summary

    Using the code and the art asset I am providing you with you can quickly create your own tether system that

    1. works with pawns with skeletal meshes

    2. can be attached to any socket on the pawn, and you can create your own sockets to use to make tether appear on any part of the body

    3. tether source is updated as pawn skeletal mesh plays animations

    4. the tether can be retracted or extended at will

    5. the Player can still control the pawn with WASD control scheme (or current console controller scheme) while it moves around in the air due to tether

    6. You can shut off all UT Pawn animations and only play animations of your choice during tethering

    7. Code Optimized to reduce creation/deletion of local vars to make algorithm faster

    8. Time dilation / fps fluctuations accounted for

    9. Smoothly transition from running and jumping into grappling, and back again with no delays

    10. Enjooooy




    Rama

    #2
    Amazing Rama!! i request you to make a fully functional grenade tutorial.

    Comment


      #3
      Very cool EverNewJoy, good on you for sharing! The simplicity of the code is great!

      Have you tried this is a network game yet? If not I think you may get a few "accessed nones" (the PlayerController won't exist on non-owning clients when the 'Tick' function is run on their local copies of the pawns, may want to toss in a "if(PC !=None)" check too). Also, is the tether endpoint replicated so that clients can see the tether in its proper location?

      Comment


        #4
        OMG!!!! Thank you very much man !!!!!!!!!!! NICE !!!

        Comment


          #5
          @MeowCat

          Originally posted by meowcat View Post
          Very cool EverNewJoy, good on you for sharing! The simplicity of the code is great!

          Have you tried this is a network game yet? If not I think you may get a few "accessed nones" (the PlayerController won't exist on non-owning clients when the 'Tick' function is run on their local copies of the pawns, may want to toss in a "if(PC !=None)" check too). Also, is the tether endpoint replicated so that clients can see the tether in its proper location?
          hahha I love the quote in your signature

          I have not delved into multiplayer game and network code myself yet, so none of my tutorials or code are even considering multiplayer yet

          I will get there though, any code you want to post to assist people who are ready for that step with my current code feel free

          nice to hear from you!



          Rama

          PS: my commentary about my code being optimized for multiplayer/replication is due to fact of its simplicity and minimum amount of data to keep track of, as opposed to rigid body simulations which can be oh so complicated.

          Comment


            #6
            Originally posted by Chihastonick View Post
            OMG!!!! Thank you very much man !!!!!!!!!!! NICE !!!
            Yaaay!!!



            Rama

            Comment


              #7
              Originally posted by ryanjon2040 View Post
              Amazing Rama!! i request you to make a fully functional grenade tutorial.
              hahahha

              that's a good point, I have grenade trajectory pathing system (including estimated bounces due to realtime geometry) all working but I've not made tutorial yet!

              I will work on this when I get some more time

              Nice to hear from you Ryan Jon!

              Rama

              Comment


                #8
                Originally posted by evernewjoy View Post
                I have grenade trajectory pathing system (including estimated bounces due to realtime geometry)
                Thats Great!!

                Originally posted by evernewjoy View Post
                I will work on this when I get some more time
                Hoping to see it soon!

                Comment


                  #9
                  I am uploading the vid for the grenade pathing tutorial right now!



                  Rama

                  Comment


                    #10
                    nice one might give this a try
                    thank you Rama
                    keep up the good work

                    Comment


                      #11
                      Great to hear from you Tegleg!

                      Thanks for all your own awesome contributions

                      Rama

                      Comment


                        #12
                        Hey Rama, I'm new to unrealscripting and I can't seem to follow this tutorial real well. I'm having trouble making your keybinding functions and getting your gameInfo class to work with the customHUD and customPlayerController. I just can't seem to put it all together the right way. If you could please post a completed code with everything together that all you have to do is copy and paste into each class file it would be a lot easier to follow. It's makes it hard to follow when some of the code is in a different tutorial section and you don't know what you need to take out of the other tutorial code to get this one to work. Please help me by posting all the necessary code I need in each class file so I can plug it into my UDK\Development\Src\MyGame\Classes\ and get this awesome grappling hook/tether to work.

                        Comment


                          #13
                          Originally posted by DMH_EAGLE View Post
                          Hey Rama, I'm new to unrealscripting and I can't seem to follow this tutorial real well. I'm having trouble making your keybinding functions and getting your gameInfo class to work with the customHUD and customPlayerController. I just can't seem to put it all together the right way. If you could please post a completed code with everything together that all you have to do is copy and paste into each class file it would be a lot easier to follow. It's makes it hard to follow when some of the code is in a different tutorial section and you don't know what you need to take out of the other tutorial code to get this one to work. Please help me by posting all the necessary code I need in each class file so I can plug it into my UDK\Development\Src\MyGame\Classes\ and get this awesome grappling hook/tether to work.
                          What you are asking is not easy for me to do or even good for you as an evolving programmer.

                          Your implementation of my tether code needs to be specific to your game setup and only you know what that is

                          I cover much more details about player controller + game info + HUD and keybinding in this tutorial

                          Third person Camera, Drag Select, Custom HUD
                          http://forums.epicgames.com/threads/...7#post31030597


                          Be patient with yourself and you will figure this out!

                          Interaction among the various classes during run-time is one of the hardest things about unrealscript to get used to.

                          But once you do, it really is quite awesome!




                          Rama

                          Comment


                            #14
                            Hey Rama,
                            I was wondering if you could help me out a touch. :3


                            I followed your tutorial, and it looks fantastic!
                            But I have a few issues, probably because of my custom setup, so I went debugging!
                            When I debug the trace line, everything looks fine.
                            But the start location of the beam becomes (0,0,Pawn.Location.Z)

                            Although if my pawn/controller location goes to the left (less than 0) the beam start starts to follow me on the X axis, but still stays at 0 on the Y.


                            Now as you can see, the X location of the beam is now following me, along with the Z, so it is definitely attached to my socket location.


                            But if I try to go any further left, from the center, or the same distance to the right from the center, it's like I have reached the max tether length, regradless of where I create it from, or where I attach it to.


                            On top of that the increase and decrease wont work correctly for my pawn, and I believe it's because of the issue above.


                            I'm hoping that when I get these few bugs worked out, then I can call the createTether from my AltFire of my crossbow,
                            and pass the attachment class' socket location, that way, it starts with the weapon, is fired by the weapon, and is released on jump.


                            I just don't have a clue what is going on :/


                            Code timeeee~~~~~~


                            PlayerController: (no tether functions in here, as I plan to enable/disable later with different default functions =])


                            Code:
                            var bool isTethering;
                            My Pawn Class:
                            Code:
                            //=============================================
                            // Tether System
                            //=============================================
                            var actor                 curTargetWall;
                            var vector                 wallHitLoc;
                            var ParticleSystemComponent                 tetherBeam;
                            var float                 tetherMaxLength;
                            var float                tetherlength;
                            var vector                 prevTetherSourcePos;
                            var SleepStepPlayerController pc;
                            var float deltaTimeBoostMultiplier;
                            var bool TetheringAnimOnly;
                            
                            
                            //these are optimization vars
                            //their values should never be relied on
                            //used to reduce variable memory allocation/deallocation
                            //this improves algorithm speed dramatically in my experience
                            var rotator r;
                            var vector vc;
                            var vector vc2;
                            
                            
                            //=============================================
                            //  Rama Tether System
                            //
                            //This code was obtained from this page
                            //
                            //http://forums.epicgames.com/threads/964242-CODE-Rama-s-Physics-Based-Retractable-Tether-Grapple-Hook-for-Skeletal-Mesh-Pawns
                            //
                            //=============================================
                            exec function increaseTether() {
                            
                            
                                if (tetherlength > tetherMaxLength) return;
                                tetherlength += 20;
                            }
                            exec function decreaseTether() {
                                
                                if (tetherlength <= 384) {
                                    tetherlength = 384;
                                    return;
                                }
                                tetherlength -= 20;
                            }
                            
                            
                            exec function detachTether() {
                                
                                curTargetWall = none;
                                
                                //beam
                                if(tetherBeam != none){
                                    tetherBeam.SetHidden(true);
                                    tetherBeam.DeactivateSystem();
                                    tetherBeam = none;
                                }
                                
                                
                                SetPhysics(PHYS_Walking);
                            
                            
                                    //state
                                SleepStepPlayerController(Controller).isTethering = false;
                            
                            
                                //make sure to restore normal pawn animation playing
                                //see last section of tutorial
                                TetheringAnimOnly = false;
                            }
                            
                            
                            exec function createTether() {
                                local vector beamHitLoc;
                                local vector hitNormal;
                                local actor wall;
                                local vector startTraceLoc;
                                //~~~ Trace ~~~
                                pc = SleepStepPlayerController(Controller);
                                vc = Vector(pc.Rotation);
                                
                                //pawn location + 100 in direction of player camera
                                startTraceLoc = Location + vc * 100;
                                
                                //trace only to tether's max length
                                wall = Self.trace(beamHitLoc, hitNormal, 
                                            startTraceLoc + tetherMaxLength * vc, 
                                            startTraceLoc
                                        );
                                        
                                        DrawDebugLine(startTraceLoc, startTraceLoc + tetherMaxLength * vc, 255,0,0, true);
                                
                                if(!Wall.isa('Actor')) return;
                                
                                //~~~~~~~~~~~~~~~
                                // Tether Success
                                //~~~~~~~~~~~~~~~
                                //Clear any old tether
                                detachTether();
                                
                                //state
                                pc.isTethering = true;
                                
                                curTargetWall = Wall;
                                wallHitLoc = beamHitLoc;
                                
                                //get length of tether from starting
                                //position of object and wall
                                tetherlength = vsize(hitLoc - Location);
                                //~~~
                                
                                //~~~ Beam UPK Asset Download ~~~ 
                                //I provide you with the beam resource to use here:
                                //requires Nov 2012 UDK
                                //Rama Tether Beam Package [Download] For You
                                tetherBeam = WorldInfo.MyEmitterPool.SpawnEmitter(
                            
                            
                                    //change name to match your imported version 
                                    //of my package download above
                                    //In UDK: select asset and right click “copy full path”
                                    //paste below
                                    ParticleSystem'ramaTetherBeam.TetherBeam', 
                                    Location + vect(0, 0, 32) + vc * 48, 
                                    rotator(HitNormal));
                            
                            
                                tetherBeam.SetHidden(false);
                                tetherBeam.ActivateSystem(true);
                                
                                //Beam Source Point
                                Mesh.GetSocketWorldLocationAndRotation('DualWeaponPoint', vc, r);
                                tetherBeam.SetVectorParameter('TetherSource', vc);
                                
                                //Beam End
                                tetherBeam.SetVectorParameter('TetherEnd', beamHitLoc);    
                            }
                            
                            
                            //these calcs run every tick while tether is active
                            //so the code is optimized to reduce
                            //variable memory allocation and deallocation
                            //I use global vars vc and vc2 as variables to store different
                            //info I need for my tether algorithm
                            
                            
                            //the other vars are also global since they are assigned values
                            //in other tether functions
                            //and their values should NOT be recalculated every tick
                            
                            
                            //~~~~~~~~~~~~~~~~~~~~~~~~~~
                            //Rama's Tether System Calcs
                            //~~~~~~~~~~~~~~~~~~~~~~~~~~
                            function tetherCalcs() {
                                
                                //~~~~~~~~~~~~~~~~~
                                //Beam Source Point
                                //~~~~~~~~~~~~~~~~~
                                //get position of source point on skeletal mesh
                            
                            
                                //set this to be any socket you want or create your own socket
                                //using skeletal mesh editor in UDK
                            
                            
                                //dual weapon point is left hand 
                                Mesh.GetSocketWorldLocationAndRotation('DualWeaponPoint', vc, r);
                                
                                //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                //adjust for Skeletal Mesh Socket Rendered/Actual Location tick delay
                            
                            
                                //there is a tick delay between the actual socket position
                                //and the rendered socket position
                                //I encountered this issue when working skeletal controllers
                                //my solution is to just manually adjust the actual socket position
                                //to match the screen rendered position
                                //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                //if falling, lower tether source faster
                                if (vc.z - prevTetherSourcePos.z < 0) {
                                    vc.z -= 8 * deltaTimeBoostMultiplier;
                                }
                                
                                //raising up, raise tether beam faster
                                else {
                                    vc.z += 8 * deltaTimeBoostMultiplier;
                                }
                                
                                //deltaTimeBoostMultipler neutralizes effects of 
                                //fluctuating frame rate / time dilation
                            
                            
                                //update beam based on on skeletal mesh socket
                                tetherBeam.SetVectorParameter('TetherSource', vc);
                                
                                //save prev tick pos to see change in position
                                prevTetherSourcePos = vc;
                                
                                
                                //~~~~~~~~~~~~~~~~~~~
                                //Actual Tether Constraint
                            
                            
                                //I dont use a RB_Constraint
                                //I control the allowed position
                                //of the pawn through code
                                //and use velocity adjustments every tick
                                //to make it look fluid
                            
                            
                                //setting PHYS_Falling + velocity adjustments every tick 
                                //is what makes this work
                                //and look really good with in-game physics
                                //~~~~~~~~~~~~~~~~~~~
                                
                                //vector between player and tether loc
                                //curTargetWall was given its value in createTether()
                                vc = Location - curTargetWall.Location;
                                
                                //dist between pawn and tether location
                                //see Vsize(vc) below (got rid of unnecessary var)
                                
                                
                                    //is the pawn moving beyond allowed current tether length?
                                    //if so apply corrective force to push pawn back within range
                                if (Vsize(vc) > tetherlength) {
                                    
                                            //determine whether to remove all standard pawn
                                        //animations and just use the Victory animation
                                        //I use this to make animations look smooth while my Tether System
                                            //is applying changes to pawn velocity (otherwise strange anims play)
                            
                            
                                            //this also results in pawn looking like it is actively initiating the
                                            //change in velocity through some Willful Action
                                            TetheringAnimOnly = true;
                                    
                                            SetPhysics(PHYS_Falling);
                                    
                                    //direction of tether = normal of distance between
                                    //pawn and tether attach point
                                    vc2 = normal(vc);
                                    
                                    //moving in same direction as tether?
                            
                            
                                    //absolute value of size difference between
                                    //normalized velocity and tether direction
                                    //if > 1 it means pawn is moving in same direction as tether
                                    if(abs(vsize(Normal(velocity) - vc2)) > 1){
                                    
                                    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                    //limit max velocity applied to pawn in direction of tether
                                    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                            
                            
                                    //50 controls how much the pawn moves around while attached to tether
                                    //could turn into a variable and control for greater refinement of
                                    //this game mechanic
                            
                            
                                    //1200 is the max velocity the tether system is allowed to force the
                                    //pawn to move at, adjust to your preferences
                                    //could also be made into a variable
                                    if(vsize(velocity) < 1200){
                                        velocity -= vc2 * 50;
                                    }
                                    }
                                    
                                    //not moving in direction of pawn
                                    //apply as much velocity as needed to prevent falling
                                    //allows sudden direction changes
                                    else {
                                        velocity -= vc2 * 50;
                                    }
                                }
                                else {
                                    //allow all regular ut pawn animations
                                            //since player velocity is not being actively changed 
                                            //by Rama Tether System
                                            TetheringAnimOnly = false;
                                }
                                /*
                                //if the target point of tether is attached to moving object
                            
                            
                                if (tetheredToMovingWall) {
                                    //beam end point
                                    tetherBeam.SetVectorParameter('TetherEnd',                     
                                    curTargetWall.Location);
                                }
                                */
                            }
                            
                            
                            //=============================================
                            // End Tether System
                            //=============================================
                            And the pawn's tick (Which is waaaaay on down xD)

                            Code:
                            simulated function Tick(float DeltaTime)
                            {
                                local vector tmpLocation;
                                super.Tick(DeltaTime);
                                
                                    //for fps issues and keeping things properly up to date
                                //specially for skeletal controllers
                            
                            
                                deltaTimeBoostMultiplier = deltatime * 40;
                                
                                //the value of 40 was acquired through my own hard work and testing,
                                //this deltaTimeBoostMultiplier system is my own idea :)
                            
                            
                                //=== TETHER ====
                                //pc is ref to controller class
                                if (pc.isTethering) {
                                    tetherCalcs();        //run calcs every tick tether is active
                                }
                                
                                tmpLocation = Location;
                                tmpLocation.Y = -1000;
                                SetLocation(tmpLocation);

                            Now I think my Y Location updates within the Tick (which I use for keeping my pawn on the correct 2D plane) are what's causing the issue with the beam start location,
                            so that should be an easy fix, by passing it that temp Location. But that's only a visual fix.


                            So I can learn, can you gimme a Hint as to what might be wrong?? That way I can fix it a feel cool


                            WHY AREN'T MY CODE TAGS WORKING CORRECTLY??
                            IT'S ALL GOING ON ONE LINE???


                            Thanks a bunch for your time Rama!
                            Peace.
                            -Loken :3

                            Comment


                              #15
                              [code] This should work... [/code]

                              Comment

                              Working...
                              X