BlazeCell
BlazeCell

Reputation: 145

Unity3D - Top Down Camera Logic Gets Locked When Using Transform.LookAt

I've put together a custom top-down camera logic script based on Unity3D's ThirdPersonCamera.js script. Everything appears to be working properly, the camera follows the target player on the XZ plane and even moves along the Y-axis as appropriate when the player jumps.

Only the camera isn't looking at the player. So I tried using Transform.LookAt() on the cameraTransform to have the camera looking directly down on the player. This does cause the camera to correctly look directly down on the player, but then movement via WASD no longer works. The player just sits there. Using Spacebar for jumping does still work though.

This doesn't make sense to me, how should the orientation of the camera's transform be affecting the movement of the player object?

The code for my script is below:

// The transform of the camera that we're manipulating
var cameraTransform : Transform;

// The postion that the camera is currently focused on
var focusPosition = Vector3.zero;

// The idle height we are aiming to be above the target when the target isn't moving
var idleHeight = 7.0;

// How long should it take the camera to focus on the target on the XZ plane
var xzSmoothLag = 0.3;

// How long should it take the camera to focus on the target vertically
var heightSmoothLag = 0.3;


private var _target : Transform;
private var _controller : ThirdPersonController;

private var _centerOffset = Vector3.zero;
private var _headOffset = Vector3.zero;
private var _footOffset = Vector3.zero;

private var _xzVelocity = 0.0;
private var _yVelocity  = 0.0;
private var _cameraHeightVelocity = 0.0;


// ===== UTILITY FUNCTIONS =====

// Apply the camera logic to the camera with respect for the target
function process()
{
    // Early out if we don't have a target
    if ( !_controller )
        return;

    var targetCenter = _target.position + _centerOffset;
    var targetHead   = _target.position + _headOffset;
    var targetFoot   = _target.position + _footOffset;

    // Determine the XZ offset of the focus position from the target foot
    var xzOffset = Vector2(focusPosition.x, focusPosition.z) - Vector2(targetFoot.x, targetFoot.z);

    // Determine the distance of the XZ offset
    var xzDistance = xzOffset.magnitude;

    // Determine the Y distance of the focus position from the target foot
    var yDistance = focusPosition.y - targetFoot.y;

    // Damp the XZ distance
    xzDistance = Mathf.SmoothDamp(xzDistance, 0.0, _xzVelocity, xzSmoothLag);

    // Damp the XZ offset
    xzOffset *= xzDistance;

    // Damp the Y distance
    yDistance = Mathf.SmoothDamp(yDistance, 0.0, _yVelocity, heightSmoothLag);

    // Reposition the focus position by the dampened distances
    focusPosition.x = targetFoot.x + xzOffset.x;
    focusPosition.y = targetFoot.y + yDistance;
    focusPosition.z = targetFoot.z + xzOffset.y;

    var minCameraHeight = targetHead.y;
    var targetCameraHeight = minCameraHeight + idleHeight;

    // Determine the current camera height with respect to the minimum camera height
    var currentCameraHeight = Mathf.Max(cameraTransform.position.y, minCameraHeight);

    // Damp the camera height
    currentCameraHeight = Mathf.SmoothDamp( currentCameraHeight, targetCameraHeight, _cameraHeightVelocity, heightSmoothLag );

    // Position the camera over the focus position
    cameraTransform.position = focusPosition;
    cameraTransform.position.y = currentCameraHeight;

// PROBLEM CODE - BEGIN

    // Have the camera look at the focus position
    cameraTransform.LookAt(focusPosition, Vector3.forward);

// PROBLEM CODE - END

    Debug.Log("Camera Focus Position: " + focusPosition);
    Debug.Log("Camera Transform Position: " + cameraTransform.position);
}

// ===== END UTILITY FUNCTIONS =====


// ===== UNITY FUNCTIONS =====

// Initialize the script
function Awake( )
{
    // If the camera transform is unassigned and we have a main camera, 
    //   set the camera transform to the main camera's transform
    if ( !cameraTransform && Camera.main )
        cameraTransform = Camera.main.transform;

    // If we don't have a camera transform, report an error
    if ( !cameraTransform )
    {
        Debug.Log( "Please assign a camera to the TopDownThirdPersonCamera script." );
        enabled = false;    
    }

    // Set the target to the game object transform
    _target = transform;

    // If we have a target set the controller to the target's third person controller
    if ( _target )
    {
        _controller = _target.GetComponent( ThirdPersonController );
    }

    // If we have a controller, calculate the center offset and head offset
    if ( _controller )
    {
        var characterController : CharacterController = _target.collider;
        _centerOffset = characterController.bounds.center - _target.position;
        _headOffset = _centerOffset;
        _headOffset.y = characterController.bounds.max.y - _target.position.y;
        _footOffset = _centerOffset;
        _footOffset.y = characterController.bounds.min.y - _target.position.y;
    }
    // If we don't have a controller, report an error
    else
        Debug.Log( "Please assign a target to the camera that has a ThirdPersonController script attached." );

    // Apply the camera logic to the camera
    process();
}

function LateUpdate( )
{
    // Apply the camera logic to the camera
    process();
}

// ===== END UNITY FUNCTIONS =====

I've marked the problem code section with PROBLEM CODE comments. If the problem code is removed, it allows WASD movement to work again, but then the camera is no longer looking at the target.

Any insight into this issue is very much appreciated.

Upvotes: 1

Views: 924

Answers (1)

BlazeCell
BlazeCell

Reputation: 145

I figured it out, the issue was with the ThirdPersonController.js script that I was using. In the function UpdateSmoothedMovementDirection(), the ThirdPersonController uses the cameraTransform to determine the forward direction along the XZ plane based on where the camera is looking at. In doing so, it zeros out the Y axis and normalizes what's left.

The cameraTransform.LookAt() call I perform in my custom TopDownCamera.js script has the camera looking directly down the Y-axis. So when the ThirdPersonController gets a hold of it and zeros out the Y-axis, I end up with zero forward direction, which causes the XZ movement to go nowhere.

Copying ThirdPersonController.js and altering the code so that:

var forward = cameraTransform.TransformDirection(Vector3.forward);
forward.y = 0;
forward = forward.normalized;

becomes:

forward = Vector3.forward;

fixed the issue.

Upvotes: 1

Related Questions