[Unity2D]实现背景的移动

本文详细介绍了如何在游戏中实现动态背景效果,包括通过脚本调整摄像机位置跟随玩家移动,以及如何为不同类型的背景设置不同的移动速度。通过提供具体的脚本示例,帮助开发者理解和实现这一功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    在游戏中通常会实现的效果是玩家主角移动的时候,背景也可以跟着移动,要实现这种效果其实就是获取主角的位置,然后再改变摄像机的位置就可以了,这就需要通过脚本来实现。这个脚本添加到摄像机的GameObject上,相当于摄像机的控制器。

using UnityEngine;
using System.Collections;

public class CameraController : MonoBehaviour
{
    public PlayerStateController.playerStates currentPlayerState = PlayerStateController.playerStates.idle;
    public GameObject playerObject = null;//玩家游戏对象
    public float cameraTrackingSpeed = 0.2f;
    private Vector3 lastTargetPosition = Vector3.zero;//玩家最后的位置
    private Vector3 currTargetPosition = Vector3.zero;//玩家当前的位置
    private float currLerpDistance = 0.0f;

    void Start()
    {
        Vector3 playerPos = playerObject.transform.position;//玩家的位置
        Vector3 cameraPos = transform.position;//相机的位置
        Vector3 startTargPos = playerPos;//玩家初始化位置

        startTargPos.z = cameraPos.z;
        lastTargetPosition = startTargPos;
        currTargetPosition = startTargPos;
        currLerpDistance = 1.0f;
    }
    
    void OnEnable()
    {
        PlayerStateController.onStateChange += onPlayerStateChange;
    }

    void OnDisable()
    {
        PlayerStateController.onStateChange -= onPlayerStateChange;
    }

    void onPlayerStateChange(PlayerStateController.playerStates newState)
    {
        currentPlayerState = newState;
    }

    void LateUpdate()
    {
        onStateCycle();

        currLerpDistance += cameraTrackingSpeed;
        // 取两个向量之间的值
        transform.position = Vector3.Lerp(lastTargetPosition, currTargetPosition, currLerpDistance);
    }

    void onStateCycle()
    {
        switch (currentPlayerState)
        {
            case PlayerStateController.playerStates.idle:
                trackPlayer();
                break;

            case PlayerStateController.playerStates.left:
                trackPlayer();
                break;

            case PlayerStateController.playerStates.right:
                trackPlayer();
                break;

            case PlayerStateController.playerStates.jump:
                trackPlayer();
                break;

            case PlayerStateController.playerStates.firingWeapon:
                trackPlayer();
                break;
        }
    }

    void trackPlayer()
    {
        Vector3 currCamPos = transform.position;//当前相机位置
        Vector3 currPlayerPos = playerObject.transform.position;//当前玩家位置

        if (currCamPos.x == currPlayerPos.x && currCamPos.y == currPlayerPos.y)//位置一样,不移动
        {
            currLerpDistance = 1.0f;
            lastTargetPosition = currCamPos;
            currTargetPosition = currCamPos;
            return;
        }

        currLerpDistance = 0.0f;

        lastTargetPosition = currCamPos;//最后的位置为相机的位置

        currTargetPosition = currPlayerPos;//当前的位置为玩家的位置

        currTargetPosition.z = currCamPos.z;
    }

    void stopTrackingPlayer()
    {

        Vector3 currCamPos = transform.position;
        currTargetPosition = currCamPos;
        lastTargetPosition = currCamPos;


        currLerpDistance = 1.0f;
    }
}

    如果要把背景的元素区分开来,不同的背景对象有不同的移动速度那么实现的方式会稍微复杂一点点。

1、首先得把背景的GameObject进行一下分类,如下所示:

2、给这个背景GameObject的分组添加一个脚本,也就是给_ParallaxLayers添加脚本,主要需要的参数就是摄像机对象、背景GameObject的分类数组、移动速度等。

脚本如下所示:

using UnityEngine;
using System.Collections;

public class ParallaxController : MonoBehaviour
{
    public GameObject[] clouds;//云层
    public GameObject[] nearHills;//近山
    public GameObject[] farHills;//远山
    public GameObject[] lava;//地面

    // 移动的速度
    public float cloudLayerSpeedModifier;
    public float nearHillLayerSpeedModifier;
    public float farHillLayerSpeedModifier;
    public float lavalLayerSpeedModifier;

    public Camera myCamera;

    private Vector3 lastCamPos;

    void Start()
    {
        lastCamPos = myCamera.transform.position;//获取相机的位置
    }

    void Update()
    {
        Vector3 currCamPos = myCamera.transform.position;
        float xPosDiff = lastCamPos.x - currCamPos.x;//计算相机x轴的变化

        adjustParallaxPositionsForArray(clouds, cloudLayerSpeedModifier, xPosDiff);
        adjustParallaxPositionsForArray(nearHills, nearHillLayerSpeedModifier, xPosDiff);
        adjustParallaxPositionsForArray(farHills, farHillLayerSpeedModifier, xPosDiff);
        adjustParallaxPositionsForArray(lava, lavalLayerSpeedModifier, xPosDiff);

        lastCamPos = myCamera.transform.position;
    }
    // 数组来存储游戏对象
    void adjustParallaxPositionsForArray(GameObject[] layerArray, float layerSpeedModifier, float xPosDiff)
    {
        // 遍历改变精灵的位置
        for (int i = 0; i < layerArray.Length; i++)
        {
            Vector3 objPos = layerArray[i].transform.position;
            objPos.x += xPosDiff * layerSpeedModifier;
            layerArray[i].transform.position = objPos;
        }
    }
}

 

另外一种实现的方案脚本:

using UnityEngine;
using System.Collections;

public class CameraFollow : MonoBehaviour 
{
    public float xMargin = 1f;        // Distance in the x axis the player can move before the camera follows.
    public float yMargin = 1f;        // Distance in the y axis the player can move before the camera follows.
    public float xSmooth = 8f;        // How smoothly the camera catches up with it's target movement in the x axis.
    public float ySmooth = 8f;        // How smoothly the camera catches up with it's target movement in the y axis.
    public Vector2 maxXAndY;        // The maximum x and y coordinates the camera can have.
    public Vector2 minXAndY;        // The minimum x and y coordinates the camera can have.


    private Transform player;        // Reference to the player's transform.


    void Awake ()
    {
        // Setting up the reference.
        // 查找玩家游戏对象
        player = GameObject.FindGameObjectWithTag("Player").transform;
    }

    // 检查边缘
    bool CheckXMargin()
    {
        // Returns true if the distance between the camera and the player in the x axis is greater than the x margin.
        // x轴变化的绝对值大于设定值
        return Mathf.Abs(transform.position.x - player.position.x) > xMargin;
    }

    // 检查边缘
    bool CheckYMargin()
    {
        // Returns true if the distance between the camera and the player in the y axis is greater than the y margin.
        // y轴变化的绝对值大于设定值
        return Mathf.Abs(transform.position.y - player.position.y) > yMargin;
    }


    void FixedUpdate ()
    {
        TrackPlayer();
    }
    
    
    void TrackPlayer ()
    {
        // By default the target x and y coordinates of the camera are it's current x and y coordinates.
        float targetX = transform.position.x;
        float targetY = transform.position.y;

        // If the player has moved beyond the x margin...
        if(CheckXMargin())
            // ... the target x coordinate should be a Lerp between the camera's current x position and the player's current x position.
            // 在当前位置和最新位置之间插值
            // Time.deltaTime 增量时间 以秒计算,完成最后一帧的时间(只读)。使用这个函数使和你的游戏帧速率无关
            targetX = Mathf.Lerp(transform.position.x, player.position.x, xSmooth * Time.deltaTime);

        // If the player has moved beyond the y margin...
        if(CheckYMargin())
            // ... the target y coordinate should be a Lerp between the camera's current y position and the player's current y position.
            targetY = Mathf.Lerp(transform.position.y, player.position.y, ySmooth * Time.deltaTime);

        // The target x and y coordinates should not be larger than the maximum or smaller than the minimum.
        // 把目标值限制在固定的范围
        targetX = Mathf.Clamp(targetX, minXAndY.x, maxXAndY.x);
        targetY = Mathf.Clamp(targetY, minXAndY.y, maxXAndY.y);

        // Set the camera's position to the target position with the same z component.
        // 设置相机的位置
        transform.position = new Vector3(targetX, targetY, transform.position.z);
    }
}

 

<think>好的,用户的问题是关于在Unity实现2D背景随相机移动的方法。首先,我需要回忆一下Unity中常见的背景跟随相机的技术手段。记得通常有几种方法,比如将背景直接设为相机的子物体,或者通过脚本控制背景的位置与相机同步。另外,视差滚动也是一种常见的方法,可以营造层次感。 用户提到的是2D游戏,可能Y轴被锁死,所以重点在X轴的移动。需要确保背景在相机移动时平滑跟随,同时避免抖动。之前用户提到的解决相机跟随鬼畜问题的方法,比如不使用Slerp而直接通过位置插值,这可能也适用于背景移动。 首先,可能需要检查用户是否了解基础的相机设置,比如相机的跟随脚本。然后考虑不同的背景类型,比如单层背景或多层视差背景。对于单层背景,直接将背景设为相机的子物体是最简单的,但如果是多层,就需要不同的移动速度来产生视差效果。 另外,用户可能遇到的问题是背景移动时的抖动,这可能与更新顺序或插值方法有关。比如,在LateUpdate中更新位置,或者使用Vector3.Lerp进行平滑插值。还要注意相机的移动方式,是否在FixedUpdate中更新,导致与背景的Update不同步。 还需要考虑性能问题,比如是否需要使用对象池来管理动态背景元素,或者使用无限滚动的纹理偏移。可能还要提到材质偏移的方法,通过调整材质的offset来实现背景移动,这对于大背景或重复纹理比较有效。 用户的问题可能还涉及到不同场景的需求,比如横向卷轴游戏或平台游戏背景移动的方式可能不同。需要给出具体的代码示例,说明如何将脚本挂载到背景物体上,并关联相机。同时提醒注意事项,比如图层顺序、渲染模式以及性能优化。 最后,生成相关问题时要覆盖扩展内容,比如优化抖动、视差实现、性能优化和无限背景等,这样用户可以根据需要进一步探索。</think>### Unity 2D背景随相机移动实现方法 #### 1. **基础跟随方法** 将背景直接设置为相机的子物体: - 在Hierarchy中将背景物体拖拽到相机对象下 - 调整背景局部坐标,使其与相机视野匹配 - 优点:简单直接,无需代码 - 缺点:仅适合单层静态背景,无法实现视差效果[^1] #### 2. **脚本同步位置** ```csharp public class BackgroundFollow : MonoBehaviour { public Transform cameraTransform; public Vector3 offset; void LateUpdate() { // 只同步X轴位置 transform.position = new Vector3( cameraTransform.position.x + offset.x, transform.position.y, transform.position.z ); } } ``` - 挂载脚本到背景物体 - 将相机拖拽到`cameraTransform`参数槽 - 通过`offset`调整背景初始位置偏移量 - 使用`LateUpdate`避免画面抖动[^1] #### 3. **视差滚动效果** ```csharp public class ParallaxBackground : MonoBehaviour { public float parallaxFactor; // (0-1) 0=静止,1=完全跟随 private Transform cam; private Vector3 previousCamPos; void Start() { cam = Camera.main.transform; previousCamPos = cam.position; } void LateUpdate() { float deltaX = (cam.position.x - previousCamPos.x) * parallaxFactor; transform.Translate(new Vector3(deltaX, 0, 0)); previousCamPos = cam.position; } } ``` - 为不同图层设置不同的`parallaxFactor` - 前景层:0.8-1.0 - 中层:0.5-0.7 - 远景层:0.1-0.4 #### 4. **无限循环背景** ```csharp public class InfiniteBackground : MonoBehaviour { public float textureUnitSize; // 纹理单位尺寸 void Start() { Sprite sprite = GetComponent<SpriteRenderer>().sprite; textureUnitSize = sprite.texture.width / sprite.pixelsPerUnit; } void LateUpdate() { if (Mathf.Abs(cam.position.x - transform.position.x) >= textureUnitSize) { float offset = (cam.position.x - transform.position.x) % textureUnitSize; transform.position = new Vector3(cam.position.x + offset, transform.position.y); } } } ``` #### 5. **材质偏移法(适合大尺寸背景)** ```csharp public class MaterialOffset : MonoBehaviour { public float scrollSpeed; private Material mat; private Vector2 offset; void Start() { mat = GetComponent<Renderer>().material; } void Update() { offset.x = (Camera.main.transform.position.x * scrollSpeed) % 1; mat.mainTextureOffset = offset; } } ``` **注意事项**: 1. 确保所有背景物体的Z轴坐标大于相机Z轴 2. 使用Sorting Layer控制渲染顺序 3. 将相机的Projection设置为Orthographic 4. 对移动频繁的背景禁用物理碰撞
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值