5
\$\begingroup\$

The player is moving automatically diagonally down the screen, and I have the camera as a child on the player. I would like the camera to always be following the player (who sometimes slows down / speeds up) as they are automatically moving, but when the player moves left and right, I don't want the whole camera view to shift with this.

I am moving the player with this:

transform.Translate(xSpeed, ySpeed, 0);

And the player can move the character with this:

Vector2 direction = new Vector2(0.2f, 0.67f);

if (Input.GetKeyDown(KeyCode.LeftArrow))
{   //transform stores the position data of the playu
    transform.Translate(direction * -distance);
}

else if (Input.GetKeyDown(KeyCode.RightArrow))
{
    transform.Translate(direction * distance);
}

However when they move with this I would like not for the camera to shift with the movement, but still continue to follow them as they move across the 2D map.

@Hash Buoy I can't add comments yet, but the player is automatically moving at an angle, which the camera follows them. They can move left and right with the arrow keys, and I was just wondering how to stop the camera shifting left and right (also as a 45 degree angle) when they do this

\$\endgroup\$
  • \$\begingroup\$ Do you mean that you want the camera to follow the player only in up and down direction and not in left and right directions ?? \$\endgroup\$ – Hash Buoy Oct 3 '15 at 12:00
2
\$\begingroup\$

So first off, you'll want to separate the player and camera in the inspector. Typically you only want to parent in that fashion when you want ALL transforms to be transferred to the children--note that if you rotate your player, or if you scale your player, the same will happen to your camera in your current setup, and that's very limiting.

Instead, you'll want to write a script that you place on the camera that manually follows your player. Like so:

public class PlayerTracker: MonoBehaviour
{
  public Transform Player;

  private Vector3 lastPos;

  void Start()
  {
    if(Player == null)
      //You'll want to maybe search the tags or something more reasonable here.
      Debug.Log("You forgot to set the player, stupid!");

    lastPos = Player.position;
  }

  void Update()
  {
    //Get the distance the player has moved since last frame.
    Vector3 delta = Player.position - lastPos;
    //Adds this difference to the camera's transform.
    this.transform.position += delta;
    //Caches the player's current position for next frame.
    lastPos = Player.position;
  }

This will match your player's movement unit for unit, while preserving the original distance between the two. But since you want to limit which axes are being used, we'll change the this.transform.position += delta; line to this instead:

this.transform.position += new Vector3(0, delta.y, 0);

And now only the Y-axis is being followed.

This is assuming a Ski-Free-like movement. I'm not quite sure what you're definitions of "diagonal", "left", and "right" are, so you'll have to clarify that for us if this isn't what you're looking for.

\$\endgroup\$
2
\$\begingroup\$

I fell into the same problem last week.

The easy solution is grabbing the Camera2Dfollow script from the standard asset package and set the target as the player. If you choose to do so, Remove the camera from inside the player from the hierarchy screen

Here is the Script :

 using System;
  using UnityEngine;

         namespace UnityStandardAssets._2D
    {
          public class Camera2DFollow : MonoBehaviour
        {
    public Transform target;
    public float damping = 1;
    public float lookAheadFactor = 3;
    public float lookAheadReturnSpeed = 0.5f;
    public float lookAheadMoveThreshold = 0.1f;

    private float m_OffsetZ;
    private Vector3 m_LastTargetPosition;
    private Vector3 m_CurrentVelocity;
    private Vector3 m_LookAheadPos;

    // Use this for initialization
    private void Start()
    {
        m_LastTargetPosition = target.position;
        m_OffsetZ = (transform.position - target.position).z;
        transform.parent = null;
    }


    // Update is called once per frame
    private void Update()
    {
        // only update lookahead pos if accelerating or changed direction
        float xMoveDelta = (target.position - m_LastTargetPosition).x;

        bool updateLookAheadTarget = Mathf.Abs(xMoveDelta) > lookAheadMoveThreshold;

        if (updateLookAheadTarget)
        {
            m_LookAheadPos = lookAheadFactor*Vector3.right*Mathf.Sign(xMoveDelta);
        }
        else
        {
            m_LookAheadPos = Vector3.MoveTowards(m_LookAheadPos, Vector3.zero, Time.deltaTime*lookAheadReturnSpeed);
        }

        Vector3 aheadTargetPos = target.position + m_LookAheadPos + Vector3.forward*m_OffsetZ;
        Vector3 newPos = Vector3.SmoothDamp(transform.position, aheadTargetPos, ref m_CurrentVelocity, damping);

        transform.position = newPos;

        m_LastTargetPosition = target.position;
    }
}

}

\$\endgroup\$
1
\$\begingroup\$

Let your camera be positioned at point c and let your player be position at point p. Let v be a vector representing the velocity moving the player on a diagonal. For every tick c_{next} = c + v, p_{next} = p + v.

One also must consider if the player moves far enough horizontally that they are outside of the view port. One method to handle this is clamping the player to the screen now allowing them to run out of the view port.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.