Dienstag, 8. Mai 2012

Unity3D: 3rd Person FPS Player Controller

Here is my player controller script in JavaScript. It is fitted to work with the camera script in the post before.

Just attach it to your Player (-Prefab).

You need to add another input axis called "Run" (default is "right shift"...)
For that, click on Edit->Project-Settings->Input and rename an axis wich you do not need.

You can move your Player now with the arrow keys or WASD. You can jump with Space and run with
the right shift key. The facing direction will be rotated to the camera forward direction, wich changes with the mouse in the camera script.

// Script by ben0bi
// regarding the ThirdPersonController from the ThirdPersonPlattformer Example Project

// The player can make jumps, doublejumps and walljumps.
// It will look where the camera looks, and turn smoothly towards it if the camera changes.
// Its "optimized" for 3rd Person FPS type games. // The script is in need for the Input Axes: "Horizontal", "Vertical", "Jump" and "Run".
// You need to add "Run" by yourself:
// In Unity: Click on Edit->Project Settings->Input - In the Inspector, name one of the axes to "Run" and
// let the positive value be "right shift". To add a new axis, just type a greater number into the size
// property at the top.

// Shooting will happen in another script.

// is the player at all controllable?
var isControllable = true;

var canJump=true; // can the player jump? if not, he can also not doublejump and walljump
var canDoubleJump=true; // can the player jump after a jump?
var canWallJump=true; // can the player jump away from a wall when touching it?
var jumpHeight = 1.5; // this is the jump height by pressing it the first time.
var doubleJumpHeight=1.0; // this height will be added to verticalspeed one the jump button is pressed the second time.

// set the jump button time variable and check for a doublejump. (=jumpButtonPressedTwice==1)
if (Input.GetButtonDown ("Jump"))
{
if(jumpButtonPressedTwice==-2) // it was set the second time..
jumpButtonPressedTwice=1; // thats a double jump
else
jumpButtonPressedTwice=-1; // set it the first time..
lastJumpButtonTime = Time.time;
}

// check if jump button was pressed the second time
if(Input.GetButtonUp("Jump"))
{
if(jumpButtonPressedTwice==-1) // set it the second time
jumpButtonPressedTwice=-2;
}

UpdateSmoothedMovementDirection();

ApplyGravity ();

// Perform a wall jump logic
// - Make sure we are jumping against wall etc.
// - Then apply jump in the right direction)
if (canWallJump)
ApplyWallJump();

faceDirection = Vector3.Slerp(faceDirection, forward,Time.deltaTime*8);
var targetDir=forward*vertical+right*horizontal*sidewayWalkMultiplier;
// Grounded controls
if (grounded)
{
// We store speed and direction seperately,
// so that when the character stands still we still have a valid forward direction
// moveDirection is always normalized, and we only update it if there is user input.
if (faceDirection != Vector3.zero)
{
moveDirection = targetDir.normalized;
}

// Smooth the speed based on the current target direction
var curSmooth = speedSmoothing * Time.deltaTime;

// Choose target speed
//* We want to support analog input but make sure you cant walk faster diagonally than just forward or sideways
var targetSpeed = Mathf.Min(targetDir.magnitude, 1.0);

function ApplyGravity ()
{
if (isControllable) // don't move player at all if not controllable.
{
// When we reach the apex of the jump we send out a message
if (jumping && !jumpingReachedApex && verticalSpeed <= 0.0)
{
jumpingReachedApex = true;
SendMessage("DidJumpReachApex", SendMessageOptions.DontRequireReceiver);
}

function CalculateJumpVerticalSpeed (targetJumpHeight : float)
{
// From the jump height and gravity we deduce the upwards speed
// for the character to reach at the apex.
return Mathf.Sqrt(2 * targetJumpHeight * gravity);
}

// This function responds to the "HidePlayer" message by hiding the player.
// The message is also 'replied to' by identically-named functions in the collision-handling scripts.
// - Used by the LevelStatus script when the level completed animation is triggered.
function HidePlayer()
{
GameObject.Find("rootJoint").GetComponent(SkinnedMeshRenderer).enabled = false; // stop rendering the player.
isControllable = false; // disable player controls.
}

// This is a complementary function to the above. We don't use it in the tutorial, but it's included for
// the sake of completeness. (I like orthogonal APIs; so sue me!)
function ShowPlayer()
{
GameObject.Find("rootJoint").GetComponent(SkinnedMeshRenderer).enabled = true; // start rendering the player again.
isControllable = true; // allow player to control the character again.
}