I’m using a modified version of the “FPSWalkerEnhanced” script. I spent a few days and changed a few things here and there to get it to work with my existing setup (PlayMaker, among other things)
I’ve noticed the character moves slower when moving towards or away from the camera (W or S), and slightly faster when moving horizontally relative to the camera (A or D).
The forward/backward motion slows down even more based on the camera’s distance from the character (zoom), so I’m thinking it’s got to be the way I’m accessing those directions relative to the camera, but I’m sure how to access that information (or change the way I’m using it) to fix the issue. I’m trying to get the character’s movement speed to be equal in all directions. If anyone has any advice, I’d be so thankful.
Here’s the script:
var walkSpeed = 6.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");
var pmove = FsmVariables.GlobalVariables.FindFsmString("Player Movement");
var cameraTransform = Camera.main.transform;
var forward = cameraTransform.TransformDirection(Vector3.forward);
forward.y = 0;
forward = forward.normalized;
// Right vector relative to the camera
// Always orthogonal to the forward vector
var right = Vector3(forward.z, 0, forward.x);
var v = Input.GetAxisRaw("Vertical");
var h = Input.GetAxisRaw("Horizontal");
var targetDirection = h * right + v * forward;
var horizontaldir = h * right;
var verticaldir = v * forward;
// 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;
var inputfix = (Camera.main.transform.right.x != 0.0 && Camera.main.transform.forward.z != 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 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.x = inputX * walkSpeed * Camera.main.transform.right.x;
moveDirection.x += inputY * walkSpeed * Camera.main.transform.forward.x;
moveDirection.z = inputX * walkSpeed * Camera.main.transform.right.z;
moveDirection.z += inputY * walkSpeed * Camera.main.transform.forward.z;
playerControl = true;
moveDirection.y = antiBumpFactor * -1;
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) {
playerControl = true;
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 * walkSpeed * Camera.main.transform.right.x;
moveDirection.x += inputY * walkSpeed * Camera.main.transform.forward.x;
moveDirection.z = inputX * walkSpeed * Camera.main.transform.right.z;
moveDirection.z += inputY * walkSpeed * Camera.main.transform.forward.z;
playerControl = true;
}
}
// 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;
}
// 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)
Any tips or guidance greatly appreciated! Thanks!
So what is the orientation of the camera with respect to the character? Is it above or below the character? Does the camera rotate round the character? And are you trying to have your character movements relative to the camera? That is, if you push on the 'w' key, then the character should go to the camera's forward? I believe lines 158 - 162 and 128 - 131 are the issue, but I need to understand the camera and the desired behavior to propose a fix.
– robertbu