- Home /
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;
Stay on moving Platforms
Have realistic Camera bob
Walk, Crouch and run speeds
Change in hieght when crouching
Vault over low walls
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.
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.
The camera bob script of the unifypedia works great (standalone script) so unless anyone has anything better i'm considering this done.
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
The on problem I find is that I don't know how to declare the speed variables in the various scripts so that they don't clash.
Im specifically refering to making the crouch/run script working with the standar character motor....any ideas on this front?
Answer by Graham-Dunnett · May 25, 2011 at 09:00 AM
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.
Allright will do, thankyou very much...will post back here If I get something working =)
Answer by Bunny83 · May 25, 2011 at 12:56 AM
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...
I was faintly aware of this allready (got the head bob working like that). However I don't know how well the standard walker script would work with the Crawl, walk and Sprint script. They have different variables so will they work together?
Hell, even if you direct me to a tutorial on this I would be greatfull.
Allright so Ill change the origional question. I do not require it as one monster script but as a set of drag in scripts that work together.
Thanks for the help, it will probably make the job easier =)
Well there are two general ways of doing that. A crouch script can either work as extention of other scripts (that have to be there otherwise it won't work) or work as substitude for other scripts. A extention would just influence other scripts and add some more functionality. A substitute script would deactivate othere similar scripts if it's active. In the case of a crouch script a substitute would handle the movement like the FPSWalker but with reduced speed and lower camera. As extention it would take care of lowering the characters size/capsule, reduce the speed of the FPSWalker and "tell" the FPSWalker to lower the camera. That needs some little adjustments of the FPSWalker but nothing big ;)
For the ease of combining the elements wanted should I simply start over? start fresh? the fpsmotor/input scripts are VERY hard for me to understand and I don't have the slightest clue as to how to edit them.
I would probably want every script to be an extension. Would probably have the base movement script and work it so everything else is just 'layers' that can be put over the top, only needing the base movement script to run.
Any idea on how to do that? Should I start fresh? or edit the existing character controller scripts?
Answer by tom1103 · Jun 10, 2012 at 07:16 PM
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 :)
Your answer
Follow this Question
Related Questions
Where can i find the first person controller if it's not in the project view 2 Answers
The 3 mono scripts that come with the First Person Controller asset are missing! 1 Answer
Is it okay to use asset store add ons with different coding language? 1 Answer
Can i use FirstPersonController asset for free? 1 Answer
What's the best way to store a reference to a script asset? 2 Answers