← Назад к вопросам

Реализовать следование камеры за персонажем

1.0 Junior🔥 271 комментариев
#C# и ООП#Unity Core#Физика и математика

Условие

Реализуйте плавное следование камеры за персонажем.

Требования

  1. Камера следует за целью с небольшим отставанием
  2. Настраиваемый offset и дистанция
  3. Плавное вращение при повороте персонажа
  4. Ограничение по осям для 2D платформера
  5. Опция look ahead в направлении движения

Варианты

  • Cinemachine подход
  • Собственная реализация с Lerp

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Решение: Следование камеры за персонажем

Архитектура

Хорошая система слежения камеры критична для комфортного геймплея. Рассмотрю оба варианта: с Cinemachine (встроенный инструмент) и ручную реализацию с Lerp.

Вариант 1: Собственная реализация (рекомендуется)

using UnityEngine;

public class CameraFollow : MonoBehaviour
{
    [Header("Target")]
    [SerializeField] private Transform target;
    [SerializeField] private bool useLocalPosition = false;
    
    [Header("Offset")]
    [SerializeField] private Vector3 offset = new Vector3(0, 2, -5);
    
    [Header("Smoothing")]
    [SerializeField] private float smoothSpeed = 5f;
    [SerializeField] private float rotationSmoothSpeed = 5f;
    
    [Header("Look Ahead")]
    [SerializeField] private bool useLookAhead = false;
    [SerializeField] private float lookAheadDistance = 5f;
    [SerializeField] private Rigidbody targetRigidbody;
    
    [Header("Constraints")]
    [SerializeField] private bool constrainX = false;
    [SerializeField] private Vector2 constrainXRange = new Vector2(-10f, 10f);
    [SerializeField] private bool constrainY = false;
    [SerializeField] private Vector2 constrainYRange = new Vector2(0f, 10f);
    
    private Vector3 desiredPosition;
    private Vector3 velocity = Vector3.zero;
    
    void LateUpdate()
    {
        if (target == null) return;
        
        UpdateCameraPosition();
        UpdateCameraRotation();
    }
    
    private void UpdateCameraPosition()
    {
        Vector3 targetPosition = target.position;
        
        // Look ahead в направлении движения
        if (useLookAhead && targetRigidbody != null)
        {
            Vector3 moveVel = targetRigidbody.velocity;
            if (moveVel.magnitude > 0.1f)
            {
                targetPosition += moveVel.normalized * lookAheadDistance;
            }
        }
        
        // Желаемая позиция камеры
        desiredPosition = targetPosition + offset;
        
        // SmoothDamp для плавного движения
        transform.position = Vector3.SmoothDamp(
            transform.position,
            desiredPosition,
            ref velocity,
            1f / smoothSpeed
        );
        
        // Ограничения
        ApplyConstraints();
    }
    
    private void UpdateCameraRotation()
    {
        Vector3 direction = target.position - transform.position;
        
        if (direction.magnitude > 0.01f)
        {
            Quaternion desiredRotation = Quaternion.LookRotation(direction);
            transform.rotation = Quaternion.Lerp(
                transform.rotation,
                desiredRotation,
                Time.deltaTime * rotationSmoothSpeed
            );
        }
    }
    
    private void ApplyConstraints()
    {
        Vector3 pos = transform.position;
        if (constrainX) pos.x = Mathf.Clamp(pos.x, constrainXRange.x, constrainXRange.y);
        if (constrainY) pos.y = Mathf.Clamp(pos.y, constrainYRange.x, constrainYRange.y);
        transform.position = pos;
    }
    
    public void SetTarget(Transform newTarget) => target = newTarget;
}

Вариант 2: Для 2D платформеров

using UnityEngine;

public class CameraFollow2D : MonoBehaviour
{
    [Header("Target")]
    [SerializeField] private Transform target;
    
    [Header("Settings")]
    [SerializeField] private float smoothSpeed = 5f;
    [SerializeField] private Vector2 offset = new Vector2(0, 1);
    
    [Header("Look Ahead")]
    [SerializeField] private bool useLookAhead = true;
    [SerializeField] private float lookAheadAmount = 2f;
    
    [Header("Bounds")]
    [SerializeField] private Vector2 minBounds = new Vector2(-10, -10);
    [SerializeField] private Vector2 maxBounds = new Vector2(10, 10);
    [SerializeField] private bool useConstraints = true;
    
    private Vector3 velocity = Vector3.zero;
    private float playerDirection = 1f;
    
    void LateUpdate()
    {
        if (target == null) return;
        
        // Определяем направление
        if (target.TryGetComponent<Rigidbody2D>(out var rb2d))
        {
            if (rb2d.velocity.x != 0)
                playerDirection = Mathf.Sign(rb2d.velocity.x);
        }
        
        UpdatePosition();
    }
    
    private void UpdatePosition()
    {
        Vector3 targetPos = target.position;
        
        if (useLookAhead)
            targetPos.x += lookAheadAmount * playerDirection;
        
        targetPos.x += offset.x;
        targetPos.y += offset.y;
        targetPos.z = transform.position.z;
        
        // SmoothDamp
        transform.position = Vector3.SmoothDamp(
            transform.position,
            targetPos,
            ref velocity,
            1f / smoothSpeed
        );
        
        // Ограничения
        if (useConstraints)
        {
            Vector3 pos = transform.position;
            pos.x = Mathf.Clamp(pos.x, minBounds.x, maxBounds.x);
            pos.y = Mathf.Clamp(pos.y, minBounds.y, maxBounds.y);
            transform.position = pos;
        }
    }
}

Вариант 3: С Cinemachine

using UnityEngine;
using Cinemachine;

public class CinemachineSetup : MonoBehaviour
{
    [SerializeField] private Transform target;
    [SerializeField] private CinemachineVirtualCamera virtualCamera;
    
    void Start()
    {
        virtualCamera = GetComponent<CinemachineVirtualCamera>();
        virtualCamera.Follow = target;
        virtualCamera.LookAt = target;
        
        var composer = virtualCamera.GetCinemachineComponent<CinemachineFramingTransposer>();
        if (composer != null)
        {
            composer.m_TrackedObjectOffset = new Vector3(0, 1, 0);
            composer.m_CameraDistance = 5f;
            composer.m_XDamping = 1f;
            composer.m_YDamping = 0.5f;
        }
    }
}

Ключевые параметры

  1. Smoothing Speed — как быстро ловит камера (5-10 оптимально)
  2. Offset — смещение от персонажа (Vector3)
  3. Look Ahead — предугадывает движение
  4. Constraints — границы сценария
  5. Rotation Speed — скорость поворота

Рекомендации

Для простых игр используй Вариант 1 или 2 (собственная реализация). Для крупных проектов с множеством камер используй Cinemachine. Параметр smoothSpeed 5-10 обычно оптимален.

Эта система обеспечивает плавное, профессиональное следование камеры.

Реализовать следование камеры за персонажем | PrepBro