1
\$\begingroup\$

I'm making a 2D sidescroller (although it's technically being made in 3D), and I need to freeze a player's position temporarily. With a RigidBody, this would be simple, but I can't think of how to do it with a First Person Controller besides saving a player's position and setting it back to that position every frame, which is very inefficient.

\$\endgroup\$
2
  • \$\begingroup\$ > which is very inefficient. -- Why? \$\endgroup\$
    – user15805
    Commented Jul 11, 2014 at 0:43
  • 1
    \$\begingroup\$ @AlexM. I thought it would be, since it has to set the position every single frame, not to mention that it might look a bit odd if it glitches out. I dunno, just my thought, and it surprises me there's no other way to do so. \$\endgroup\$
    – Chris
    Commented Jul 11, 2014 at 1:11

3 Answers 3

1
\$\begingroup\$

Save the linear velocity and angular velocity. Then zero them out on the rigid body. The reapply them when you're ready for the body to move again. Something like a coroutine will work just fine (mine is written in C#, but you can convert it easily enough):

void Update() {
    if (Input.GetKeyDown(KeyCode.T)) {
        StartCoroutine(PauseMovement());
    }
}

IEnumerator PauseMovement() {
    //Backup and clear velocities
    Vector3 linearBackup = rigidbody.velocity;
    Vector3 angularBackup = rigidbody.angularVelocity;
    rigidbody.velocity = Vector3.zero;
    rigidbody.angularVelocity = Vector3.zero;

    //Finally freeze the body in place so forces like gravity or movement won't affect it
    rigidbody.constraints = RigidbodyConstraints.FreezeAll;

    //Wait for a bit (two seconds)
    yield return new WaitForSeconds(2);
    //And unfreeze before restoring velocities
    rigidbody.constraints = RigidbodyConstraints.None;
    //restore the velocities
    rigidbody.velocity = linearBackup;
    rigidbody.angularVelocity = angularBackup;
}
\$\endgroup\$
9
  • \$\begingroup\$ Sorry, I just re-read your question, are you not using a rigid body at all? This will work even if there's a rigid body and a character controller. \$\endgroup\$
    – House
    Commented Jul 11, 2014 at 1:13
  • \$\begingroup\$ um, no. I'm using a slightly modified Third Person Controller, which doesn't have a RigidBody, as far as I know. \$\endgroup\$
    – Chris
    Commented Jul 11, 2014 at 1:23
  • 1
    \$\begingroup\$ Well, if you've modified the Third Person Controller, why not modify it further to do something similar to the above? Save the velocities, wait a few seconds, then reapply them. \$\endgroup\$
    – House
    Commented Jul 11, 2014 at 1:25
  • \$\begingroup\$ I'm not sure how to do that, honestly, I've just started working with Unity (and in JavaScript, haven't tried C#) so I'm sorry if I'm not fully understanding what you're saying. \$\endgroup\$
    – Chris
    Commented Jul 11, 2014 at 1:27
  • \$\begingroup\$ No worries. So the problem you're having is that the character continues to move. It's moving because it either has velocity, or input commands changing the position. For input commands it's easy to just have a bool set for the duration of the freeze that tells the controller not to accept input. For velocity you'll want to save the velocity to a back up variable, then zero out the variable that's being used to update the position (meaning the position won't change anymore), wait for a bit, then restore the velocity so the position can be updated again as before the freeze. \$\endgroup\$
    – House
    Commented Jul 11, 2014 at 1:31
0
\$\begingroup\$

Just don't use the First-Person controller that Unity comes with. It's simply a pre-written script attached to a Character Controller; you could easily just write your own movement script (that's what I do, and it's the second chapter of the book I'm writing).

Since the movement is simply a batch of code within a script you wrote, then any time you don't want to move the object simply don't run that code. Just wrap all the movement code with if (canMove) { and then set canMove = false when you want to player to freeze.

(incidentally, if you're making a 2D side-scroller then why are you using a first-person controller? forgive me making the obvious point, but er your game isn't first-person)

\$\endgroup\$
1
  • \$\begingroup\$ I just found it easy to work with, it's all premade and ready to go. I just removed the camera and tweaked the movement script a bit and I was good. It has Moving Platforms, gravity, pretty much everything premade. \$\endgroup\$
    – Chris
    Commented Jul 14, 2014 at 22:29
0
\$\begingroup\$

I am no expert but I have just done this in C# (freeze the player for 2 seconds as penalty) handled through a canMove bool around the movement handler. I thought this was the easiest way to do this and so far it has served me just fine!

Before the movement handling loop:

if (player.status == penalised)
{ 
   if (checkerVar >= (levelTimer - 2) 
      player.status = normal
}

This bit sets the player status to normal if it's been 2 seconds since the checkerVar is set (which happens when hitting a wall in my case). LevelTimer is an independent variable that counts down from when the level begins.

else 
{
    // handle all movement
    bool canMove = false;
    switch (playerAction)
    case (tile in the direction the player wants to move in == tileType::WALL)
 {
      player.status = penalised;
      checkerVar = levelTimer;
 }
case (tile in the direction the player wants to move in == tileType::FLOOR)
      canMove = true;
      // etc for all other directions

// canMove is only set to true when the player is not hitting a wall
if (canMove)
{
    player.move();
}

Granted, I found this way easy because I already had a level timer to work with, so penalising the player by counting seconds was quite straightforward. FWIW rendering for me (2D) happens in a separate function, where I use the status of the player to render a different skin if they are penalised - nothing else. Hope this helps!

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .