Advanced/Dynamic First Person Controller

Hey all,

First, my prediciment. The Firstpersoncontroller that comes with the standard unity assets is fine but not A. very realistic and B. Is not dynamic. I believe that a more interesting character controller would be much loved by the community. There are plenty of scripts out there allready that can do this, they just need to be brought together.

This does not need to be one large monster script. Preferably it would be 6 or more seperate scripts that could be dragged onto a standard firstpersoncontroller to allow for some customisation.

What I want the first person controller to be able to do is this;

  1. Stay on moving Platforms
  2. Have realistic Camera bob
  3. Walk, Crouch and run speeds
  4. Change in hieght when crouching
  5. Vault over low walls
  6. Climb large walls/ladders

Now i’m very new to coding and so have very little idea what im doing but I now enough to now a vague direction to take this. I would like the code to be in javascript (if possible).

Now i’m also very aware there are lots of scripts that do what I want out there. Problem is I have no idea how to combine them effectively. I’m going to list what still needs to be done.

  1. Allready solved by the standard charactermotor script in standard assets. Not sure how compatable the standard motor script is with the other scripts I want to impliment.
  2. The camera bob script of the unifypedia works great (standalone script) so unless anyone has anything better i’m considering this done.
  3. For this I wanted to impliment something like this script Crawl, Walk and Sprint movement speeds

    Here my first major problem rises. I have tried (using my limited knowledge, without any sucess) to combine the two scripts. Anyone that can get that workig is a far greater coder than I =).

4: For this I want to impliment the script in the answer. This is probably painfully easy but I can’t get it working How To Make The FPS Character Crouch.

This would need to be assigned to the same button as the crouch speed button from the script above.

5: Imagine this; You walk up to hip high wall and the normal jump function can’t get over it. You move back to get a runup then charge at the wall. You hold a button and hit an invisible trigger. This triggers you to get an extra boost of speed an hight. All to simulate you ‘vaulting’ over a wall. Now it has been suggested to me that I should use rigidbody.Addforce. How would I do it? It would probably be an if statement looking for trigger collision and GetButtonDown triggering two addforces (up and forward) but im not sure.

6: A bit like the one before I want the character to be able to scale select walls with invisible triggers. Something like this Programming Wall Climbing

If no-one feels like helping with this I understand…I don’t think its an easy project. I believe that if the community comes together on this however, we could have an incredibly dynaic and interesting character controlled in a very short amount of time.

Any help would be greately appreciated.

regards,

Riley Morse

Unity Answers is really for specific questions with specific answers. This kind of rallying the community to solve the problem you have is probably best handled on the Forum over at forum.unity3d.com.

What’s the point in combining all that behaviours into one single monster script?

The strategy pattern used by unity allows you to create simple behaviour script that takes care of a single task. eg. the view-bob. If you implement the view-bob as an own script that does nothing else you can just stack them together as you need it. If you implement all those tasks in a single script, tomorrow there will be someone else who needs exactly the same things you’ve done in your script but he don’t need/want the view-bobbing. So he has to edit the script and remove/change parts of the script.

Unity’s sample scripts like the FPSWalker and CharacterMotor are even two splitted classes. One just takes care of the basic movement, gravity and all related to the movement. The other (FPSWalker) just takes care of thing relevant for a FPS character: the camera and the input how it’s controlled.

Unfortunately most people don’t create versatile scripts because they code it the way they need it.

In the end it seems you begging for someone to implement 6 things that you need…

Hi I have a script for you but it is only running and walking.

var walkSpeed = 6.0; var runSpeed = 11.0;

// If true, diagonal speed (when
strafing + moving forward or back)
can’t exceed normal move speed;
otherwise it’s about 1.4 times faster
var limitDiagonalSpeed = true;

// If checked, the run key toggles
between running and walking. Otherwise
player runs if the key is held down
and walks otherwise // There must be a
button set up in the Input Manager
called “Run” var toggleRun = false;

var jumpSpeed = 8.0; var gravity =
20.0;

// Units that player can fall before a
falling damage function is run. To
disable, type “infinity” in the
inspector var fallingDamageThreshold =
10.0;

// If the player ends up on a slope
which is at least the Slope Limit as
set on the character controller, then
he will slide down var
slideWhenOverSlopeLimit = false;

// If checked and the player is on an
object tagged “Slide”, he will slide
down it regardless of the slope limit
var slideOnTaggedObjects = false;

var slideSpeed = 12.0;

// If checked, then the player can
change direction while in the air var
airControl = false;

// Small amounts of this results in
bumping when walking down slopes, but
large amounts results in falling too
fast var antiBumpFactor = .75;

// Player must be grounded for at
least this many physics frames before
being able to jump again; set to 0 to
allow bunny hopping var
antiBunnyHopFactor = 1;

private var moveDirection =
Vector3.zero; private var grounded =
false; private var controller :
CharacterController; private var
myTransform : Transform; private var
speed : float; private var hit :
RaycastHit; private var fallStartLevel
: float; private var falling = false;
private var slideLimit : float;
private var rayDistance : float;
private var contactPoint : Vector3;
private var playerControl = false;
private var jumpTimer : int;

function Start () {
controller = GetComponent(CharacterController);
myTransform = transform;
speed = walkSpeed;
rayDistance = controller.height * .5 + controller.radius;
slideLimit = controller.slopeLimit - .1;
jumpTimer = antiBunnyHopFactor;
oldPos = transform.position; }

function FixedUpdate() {
var inputX = Input.GetAxis(“Horizontal”);
var inputY = Input.GetAxis(“Vertical”);
// If both horizontal and vertical are used simultaneously, limit speed
(if allowed), so the total doesn’t
exceed normal move speed
var inputModifyFactor = (inputX != 0.0 && inputY != 0.0 && limitDiagonalSpeed)? .7071 : 1.0;

if (grounded) {
    var sliding = false;
    // See if surface immediately below should be slid down. We use this

normally rather than a
ControllerColliderHit point,
// because that interferes with step climbing amongst other
annoyances
if (Physics.Raycast(myTransform.position,
-Vector3.up, hit, rayDistance)) {
if (Vector3.Angle(hit.normal, Vector3.up)

slideLimit)
sliding = true;
}
// However, just raycasting straight down from the center can fail
when on steep slopes
// So if the above raycast didn’t catch anything, raycast down
from the stored ControllerColliderHit
point instead
else {
Physics.Raycast(contactPoint +
Vector3.up, -Vector3.up, hit);
if (Vector3.Angle(hit.normal, Vector3.up)
slideLimit)
sliding = true;
}

    // If we were falling, and we fell a vertical distance greater than

the threshold, run a falling damage
routine
if (falling) {
falling = false;
if (myTransform.position.y < fallStartLevel -
fallingDamageThreshold)
FallingDamageAlert (fallStartLevel -
myTransform.position.y);
}

    // If running isn't on a toggle, then use the appropriate speed

depending on whether the run button is
down
if (!toggleRun)
speed = Input.GetKeyDown(“LeftShift”)?
runSpeed : walkSpeed;

    // If sliding (and it's allowed), or if we're on an object

tagged “Slide”, get a vector pointing
down the slope we’re on
if ( (sliding && slideWhenOverSlopeLimit) ||
(slideOnTaggedObjects &&
hit.collider.tag == “Slide”) ) {
var hitNormal = hit.normal;
moveDirection = Vector3(hitNormal.x, -hitNormal.y,
hitNormal.z);
Vector3.OrthoNormalize (hitNormal, moveDirection);
moveDirection *= slideSpeed;
playerControl = false;
}
// Otherwise recalculate moveDirection directly from axes,
adding a bit of -y to avoid bumping
down inclines
else {
moveDirection = Vector3(inputX * inputModifyFactor,
-antiBumpFactor, inputY * inputModifyFactor);
moveDirection = myTransform.TransformDirection(moveDirection)

  • speed;
    playerControl = true;
    }

      // Jump! But only if the jump button has been released and player
    

has been grounded for a given number
of frames
if (!Input.GetButton(“Jump”))
jumpTimer++;
else if (jumpTimer >= antiBunnyHopFactor) {
moveDirection.y = jumpSpeed;
jumpTimer = 0;
}
}
else {
// If we stepped over a cliff or something, set the height at which
we started falling
if (!falling) {
falling = true;
fallStartLevel = myTransform.position.y;
}

    // If air control is allowed, check movement but don't touch the y

component
if (airControl && playerControl) {
moveDirection.x = inputX * speed * inputModifyFactor;
moveDirection.z = inputY * speed * inputModifyFactor;
moveDirection = myTransform.TransformDirection(moveDirection);
}
}

// Apply gravity
moveDirection.y -= gravity * Time.deltaTime;

// Move the controller, and set grounded true or false depending on

whether we’re standing on something
grounded = (controller.Move(moveDirection *
Time.deltaTime) &
CollisionFlags.Below) != 0; }

function Update () {
// If the run button is set to toggle, then switch between walk/run
speed. (We use Update for this…
// FixedUpdate is a poor place to use GetButtonDown, since it doesn’t
necessarily run every frame and can
miss the event)
if (toggleRun && grounded && Input.GetButtonDown(“Run”))
speed = (speed == walkSpeed? runSpeed : walkSpeed); }

// Store point that we’re in contact
with for use in FixedUpdate if needed
function OnControllerColliderHit (hit
: ControllerColliderHit) {
contactPoint = hit.point; }

// If falling damage occured, this is
the place to do something about it.
You can make the player // have
hitpoints and remove some of them
based on the distance fallen, add
sound effects, etc. function
FallingDamageAlert (fallDistance :
float) {
Debug.Log (“Ouch! Fell " + fallDistance + " units!”); }

@script
RequireComponent(CharacterController)

You need to look out by the running Input you need to change it a little but I think you can do it by yourself :slight_smile: