Announcement

Collapse
No announcement yet.

Spoof's Awesome Interpolator, Precision & Versatility, Ex:Rotate actor to face camera

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

  • replied
    bump for community, see the video for living example of Spoof's interpolator

    I made algorithm a tinnnny bit faster by getting rid of Endtime - Starttime and just saving the Duration as a global var

    saves a simple subtraction every tick.

    Rama

    Leave a comment:


  • replied
    In my most recent video(starting about 7min in) you can see Spoof's interpolator in action.

    I was using FInterpEaseInOut() with Spoof's time based interpolator for the rolling that you see the enemy critters doing to deflect attacks.

    it was actually very important that I use Spoof's time based interpolator because the critters are immune to damage while they are rolling, and so I want to guarantee that they are only rolling for say 1 second or 0.5 seconds, and not ever having a longer roll or shorter roll due to FPS / deltatime.

    Additionally, in my game editor, I can SET the time for how long each individual critter's deflective roll should be to anything, 0.5 seconds, 2 seconds, etc, and because of Spoof's time based interpolator this is extremely easy for me to implement! I just enter the desired duration in my UI and it's done!

    I also used spoof's improved RLerp, for having the enemy critters always face the player ball in full 3D (so if they are above they look down at player, etc).

    And the critters do rotate to face player while they are also rolling to deflect attacks, see Spoof's post for why his Rlerp is better for things like that.

    Thank you Spoof!



    Rama

    Leave a comment:


  • replied
    I am using Self. for the clarity of reading the code, but everyone please consider Nonder's statement.

    I could not find any info about Self. slowing down the code myself though.

    Rama

    PS: nevermind I found something by Wombo on the subject:

    "Java/C++ "this" is "self" in UnrealScript. You should avoid using it though, unless you want to pass a reference to the object executing the code to a function or assign it to a variable. The reason is that the UnrealScript compiler performs no optimization whatsoever, so while "Self.something" is usually equivalent to "something", it is a tiny little bit more expensive."

    Thanks for the info Nonder!

    Leave a comment:


  • replied
    I read somewhere that using self. can slow down your code and unrealscript does not support it like other languages. You should use simple SetRotation().

    btw. I read first time here there is something wrong with deltatime... I think it is working as expected.

    Leave a comment:


  • replied
    Updated with Spoof's new version of Rlerp

    this is especially useful to me Spoof, because my game critters can indeed rotate in 6 axis of freedom at any time, and they continually do as my game critters can move similar to a space shooter in 3D, so the player character and the enemy critters are free to roam and rotate in 6 axis continuously.

    perfect for me!

    thanks Spoof!

    Rama

    Leave a comment:


  • replied
    @ Misk84

    All is well

    have a great day!

    Rama

    PS: hope it's clear you can run the interp function many times, it restarts itself if it is not already running and there is a difference between the angle to player camera and actor rotation.

    Leave a comment:


  • replied
    And w once at a time I meant per instance of course.

    Leave a comment:


  • replied
    Ah. I read "within the actor class" like you added the code snippet to actor.uc
    Then, no complaint.

    Leave a comment:


  • replied
    @Misk84

    I've already got this code working flawlessly in my game on many many actors, the shootable creatures in my game.

    My code runs fine, many many times for each actor.


    Everything I share with you I test in my game itself

    so I know it works



    Rama

    PS: I am not changing any native actor classes

    Leave a comment:


  • replied
    Hi.
    I just had a look over your tutorial and saw you already mentioned the flaw of it being only usable once a time. I also was told recently that changing native classes like actor may lead to crashes caused by the memory management might become corrupted.

    So just a little idea. Why don't put the functionality in a separate class(actor type for the ticks sake) that, after you spawned it, takes the actor and your params ONCE and does your interpolation, and afterwards destroys itself.

    Leave a comment:


  • Spoof's Awesome Interpolator, Precision & Versatility, Ex:Rotate actor to face camera

    UPDATE:

    Spoof the pro software engineer released a new version of RLerp!

    He mentioned how it is especially useful in games where the critters can move in 6 axis of freedom.

    I added this code to my version of Spoof's interpolator below.

    ~~~

    Dear Community,

    In this thread I am providing you with an implementation of Spoof's interpolator which allows for interpolations based on game world seconds rather than deltatime.

    Precision: This means you can completely control the interpolation and it will not be affected by drops in game frame rate.

    Additionally, many of the Unrealscript functions use Alpha, a value between 0 and 1, instead of deltatime, which is inconvenient in pawn/actor classes.

    Versatility: Spoof's interpolator resolves this issue.

    Lastly, I was encountering some visual flicker using RLerp and RInterpTo, the UnrealScript interpolators.

    I modified Spoof's interpolator to get rid of this flicker issue!

    My contribution: This was a visual improvement for my game beyond even the unrealscript functions.

    Fully functional code sample provided below.

    ~~~

    Interpolators

    IF you are not familiar with Interpolators for unrealscript, they are awesome!

    They enable you to rotate or move an object over a period of time from one value to another.

    this is great for smooth rotation and moving of pawns for example.

    They can also be used for blending materials to cause a smooth transition over time.

    Here is a list of all the interpolators build into unrealscript already:
    http://wiki.beyondunreal.com/UE3:Obj...nterpEaseInOut

    ~~~

    How to Use UnrealScript Interpolators

    Here's a sample usage in tick() of an actor (a pawn for example):

    Code:
    Simulated Function tick( Float DeltaTime ) {
      //rotates this actor to face the player camera
      Self.SetRotation(RInterpTo(Self.Rotation, PlayerController.Rotation, 
             deltatime, 0.7));
    }
    Tick runs every frame, so it is running A LOT.

    So the above code that sets the actor's rotation is running very fast, with the result of a smooth appearance of motion.


    Tick() is always told the following by unrealscript:
    deltatime = the time interval in seconds between ticks.

    Keep in mind that deltaTime can always be changing, as the resources being used by the computer to render the game change, as well as in-game changes to the scene that cause lower frame rate.

    So RInterpTo in the code above says "Set this actor's rotation to some rotation between its current and the PlayerCamera rotation, here is the current time between ticks and here is the desired speed."

    If there is a drop in frame rate, deltatime will be larger, as the whole game is running slower so each tick() function call is spaced out further.

    This means that the results of RInterpTo in-game are affected by changes in the frame rate of the game; so you cannot exactly know what position the rotating actor will be in at any given time, since its position is not based on game world seconds, but is based on the change in time between ticks

    So what if you want to exactly determine how long you want one of these interpolations to last?

    And what if you don't want drops in frame rate, which affect delta time in Tick(), to influence how long the interpolation takes?

    What if you want to be able to exactly say "at game time 15.7 seconds, the actor will be facing the player camera after having completed a linear interpolation over 3 game seconds to that rotation"

    Well!

    Now we come to Spoof's awesome interpolator!

    I found this forum post by Spoof and decided to fully implement what he was suggesting.

    He wrote code that allows for an interpolator based on Game Seconds, rather than relying on just delta time, or an alpha value between 0 and 1.

    This means that using his interpolator you can say "I want this interpolation to last 2 seconds and I want the actor at this position at world time 11 seconds"

    Spoof: "A completely alternative method, and one I prefer, is to use time to control Alpha directly, using fixed values of A and B. This requires a little extra setup, but is completely deterministic, and automatically supports both delta time and time dilation effects."

    Code:
    var float StartTime, EndTime, A, B;
    
    function Go( float inA, float inB, float Duration )
    {
        A = inA;
        B = inB;
        StartTime = WorldInfo.TimeSeconds;
        EndTime = StartTime + Duration;
    }
    
    
    event Tick()
    {
        float t;
    
        t = ( EndTime - StartTime ) / ( WorldInfo.TimeSeconds - StartTime );
    
        if ( t >= 1 )
        {
            result = B;
            // TODO: stop the interpolation
        }
        else
        {
            result = Lerp( Start, End, t );
        }
    }
    ~~~

    My Implementation of the Spoof Interpolator

    This is my version of what Spoof wrote above, that allows for what he is saying, completely "deterministic" linear interpolation where you can exactly know in advance how many game seconds a liner interpolation will take, so after a smooth in-game linear rotation you can know/determine exactly what rotation an actor should have at say game time 12.3 seconds.

    My Contribution, No More Flicker:

    Even using RLerp I was getting some flicker on my actor that I was rotating, I was using a spawnable static mesh as my actor.

    I modified my implementation of Spoof's interpolator to remove the flicker I was experiencing with it as well, the exact same behavior as RLerp, until I made my modification.

    ~~~

    Fully Functional Code to Rotate Actor to Face Camera

    For this fully functional code example, whatever actor class you put this code in, each instance of the actor will always rotate to face the player camera over time.

    To clarify, you are not putting this in Actor.uc (as per a comment below).

    You are putting this code in your custom class that extends some class that extends Actor, like Pawn for example.

    Note the global vars below

    These are needed because you cannot use SetTimer on a function that has parameters.
    http://wiki.beyondunreal.com/UE3:Act...(UDK)#SetTimer

    The reason I am using SetTimer is because tick() is for the Actor, and we may not always need to have the Spoof Interpolator running.

    So I chose to implement Spoof's code as a timer within the actor class.

    Code:
    // ========= SpoofInterp Vars =========
    var Rotator startValue;
    var Rotator endValue;
    var Rotator currentValue;
    var float StartTime, EndTime, DurationTime;
    var bool SpoofInterpRunning;
    
    //spoof's RLerp using quaternions
    static function Rotator RLerpQuat( Rotator A, Rotator B, float Alpha, bool bShortestPath )
    {
        return QuatToRotator( QuatSlerp( QuatFromRotator( A ), QuatFromRotator( B ), Alpha, bShortestPath ) );
    }
    
    function startSpoofInterp( rotator inA, rotator inB, float Duration )
    {
            //restarts spoof Interpolater
    	//if run again before SpoofInterp gets to t == 1
    	
            DurationTime = Duration;	
    	startValue = inA;
    	EndValue = inB;
    	
    	StartTime = WorldInfo.TimeSeconds;
    	EndTime = StartTime + Duration;
    	
    	SetTimer(0.01, true, 'SpoofInterp');
    	
            SpoofInterpRunning = true;
            //could use isTimerActive('SpoofInterp') instead
           //to always know if SpoofInterp is running
    	
    }
    function SpoofInterp() {
    	
      local float t;
    
       //for debugging, lets you know when the actor is in the process
       //of rotating, and spoofInterp is running successfully
      `log("time"$WorldInfo.TimeSeconds);
      
      //based on current time, decide where the actor should be on
       //scale of 0 to 1 toward 1 = final destination
       
        t = ( WorldInfo.TimeSeconds - StartTime ) / ( DurationTime );
    
       //so if the interp was told to run at gameTime 10 for 2 seconds
       //and 1 second has elapsed, that means we are halfway to goal
       //so the interpolation should be at 1/2 = 0.5 using equation above
    
        //>= 1 means we are at or beyond the desired duration for this interpolation, so finish
        if ( t >= 1 )
        {
            currentValue = endValue;
            ClearTimer('SpoofInterp');
    	SpoofInterpRunning = false; //not needed if use isTimerActive
        }
        else
        {
            //replace with other interp func as needed
    	currentValue =RLerpQuat( startValue, EndValue, t );
        }
    	
       //My Contribution
       //makes effect more smooth visually to exclude fringe values
       //adjust this depending on the precision required
       //This is how I removed the flicker I was getting even using RLerp
       if (Vsize(Vector(Self.Rotation) - Vector(currentValue)) < 0.016) {
          return;
       }
    	
       //update Actor's Rotation/Position     
       SetRotation(currentValue);
    }
    
    function tick(float deltatime) {
    	local Rotator angletoCamera;
    	
            //if you are extending a class that has tick() contents you need
            super.tick(deltatime);
    
    	//get angle between this actor location and the player camera location
    	angletoCamera = Rotator(playercontroller.Location - Self.Location);
    	
    	//if this actor is not facing the camera
    	if(Self.Rotation != angletoCamera){
    		
    	  //start the SpoofInterpolator
    	  if(!SpoofInterpRunning){
    	    startSpoofInterp(Self.Rotation, angletoCamera, 1.2);
    	  }
    	  //the joy of the Spoof Interpolator
    	  //is that you can determine exactly how long
    	  //you want the interpolation to take
    		
    	  //here it is set to take 1.2 seconds;
    	}
    }
    The line
    Code:
    if(!SpoofInterpRunning){
    Is extreeemely important, otherwise the global vars are changed every tick so the duration is irrelevant.


    Note that the "Self." is not required but I use it for clarity.

    How to Make This Code Work

    This code will work as long as you know how to get your player controller class instance into this Actor's tick(). I can recommend
    Code:
    ForEach WorldInfo.AllControllers(class'PlayerController', PlayerController)
        {
          LocalPlayer = LocalPlayer(PlayerController.Player);
        }
    as a baseline starting point till you have more precise code tailored to your project.

    Note this will cycle through all players and the actor in this example will always be looking at the last active playercontroller in the world.

    ~~~

    Thank You Spoof

    -If you want to be able to use any of these interpolation functions (http://wiki.beyondunreal.com/UE3:Obj...nterpEaseInOut) for your actors, many of which don't use deltatime but instead use a value between 0 and 1, Spoof's Interpolator is ideal!

    -If you want to know exact interpolation positions at exact world times, Spoof's Interpolator is the best!

    -And if you want to be free of frame rate drops affecting your in-game interpolations, Spoof's Interpolator is a must.

    And finally, my personal favorite:

    As a programmer, I want to be able to say "take this many seconds to do this rotation" and know that's what the actor will do.

    This is only possible using Spoof's Interpolator which is reliant not on an alpha of 0 to 1, not on random strange ever-changing beast called DeltaTime, but instead on the hard simple concrete fact of actual in-game world seconds.





    Rama
Working...
X