如何为在播放模式下实例化并在 Unity 3d 中使用相机位置重新创建的对象添加视差

Posted

技术标签:

【中文标题】如何为在播放模式下实例化并在 Unity 3d 中使用相机位置重新创建的对象添加视差【英文标题】:How to add parallax to objects instantiated in play mode and recreated with camera position in Unity 3d 【发布时间】:2019-03-24 18:55:04 【问题描述】:

所以我无尽的 2d 游戏在背景中有 2 层山脉,我想在上面添加视差,近层需要比演员/相机慢,而远层要最慢。问题是,我不能直接向它们添加动作脚本,因为它们是根据随机主题颜色在播放模式下随机实例化的,所以它们是从下面的脚本中一个接一个地创建的,但我想添加一个动作在 x 轴上比相机速度慢,同时让它在最后一个结束时连续重新创建。

这是创建新山脉的脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PathManager : MonoBehaviour 

public static PathManager Instance;
public GameObject CoinFragments;
public GameObject SlideArrow;

public float parallaxSpeed = 5f; //

private GameObject lastPathObject;
private float PathXPosition;

private GameObject lastMountainFar;
private float MountainFarXPosition;
private GameObject lastMountainNear;
private float MountainNearXPosition;

private float StarXPostion;

private float lastCameraX;  //

// Use this for initialization
void Start () 
    Instance = this;


// Update is called once per frame
void Update()





private void LateUpdate()

    // Check for new Near Mountain
    if (lastMountainNear != null && GamePlayCameraManager.Instance.MainCamera.transform.position.x > lastMountainNear.transform.position.x)
    
        this.GenerateNearMountain();
    

    // Check for new Far Mountain
    if (lastMountainFar != null && GamePlayCameraManager.Instance.MainCamera.transform.position.x > lastMountainFar.transform.position.x)
    
        this.GenerateFarMountain();
    




// Start Creating Mountains
public void StartMountainCreation()
    MountainNearXPosition = GamePlayCameraManager.Instance.MainCamera.transform.position.x;
    MountainFarXPosition = GamePlayCameraManager.Instance.MainCamera.transform.position.x;
    this.GenerateNearMountain();
    this.GenerateFarMountain();


private void GenerateNearMountain()
    Vector3 MountainPosition = new Vector3(MountainNearXPosition - 4f, -3.6f, 10f);
    lastMountainNear = Instantiate(ThemeManager.Instance.SelectedMountainNear, MountainPosition, Quaternion.identity);
    MountainNearXPosition = MountainNearXPosition + lastMountainNear.GetComponent<Renderer>().bounds.size.x - 0.01f;

    //float deltaX = GamePlayCameraManager.Instance.MainCamera.transform.position.x - lastCameraX;
    //lastCameraX = GamePlayCameraManager.Instance.MainCamera.transform.position.x;
    //lastMountainNear.transform.position += Vector3.right * (deltaX * parallaxSpeed);


private void GenerateFarMountain()
    Vector3 MountainPosition = new Vector3(MountainFarXPosition - 4f, -3.6f, 22f);
    lastMountainFar = Instantiate(ThemeManager.Instance.SelectedMountainFar, MountainPosition, Quaternion.identity);
    MountainFarXPosition = MountainFarXPosition + lastMountainFar.GetComponent<Renderer>().bounds.size.x - 0.01f;

这是我的相机移动脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GamePlayCameraManager : MonoBehaviour 

public static GamePlayCameraManager Instance;   // Singleton Instance
public Camera MainCamera;   // Main Camera

private Vector3 offset;

// Use this for initialization
void Start () 
    Instance = this;
    MainCamera.transform.position = new Vector3(0, 0, -10);


// Update is called once per frame
void Update () 



void LateUpdate()

    if (GameStateManager.GameState == GameState.Set || GameStateManager.GameState == GameState.Playing)
        MainCamera.transform.position = new Vector3(this.offset.x + ActorManager.Instance.Actor.transform.position.x + 0.8f, 0, -10);


// Fixed Update Method
void FixedUpdate()



public void FindCameraOffset()
    this.offset = ActorManager.Instance.Actor.transform.position - MainCamera.transform.position + new Vector3(1.5f, 0f, 0f);


【问题讨论】:

【参考方案1】:

首先,您应该查看pooling 您的山对象,这样您就不会无休止地浪费cpu 和内存来创建它们。

一旦您将它们汇集到您的PathManager 中,您首先需要知道相机在最后一帧中移动了多远,然后告诉山据此移动。您必须在相机管理器中引用您的 PathManager

在您的相机经理的LateUpdate

if (GameStateManager.GameState == GameState.Set || GameStateManager.GameState == GameState.Playing)      
    Vector3 newPosition = new Vector3(this.offset.x + ActorManager.Instance.Actor.transform.position.x + 0.8f, 0, -10);
    float cameraMoveAmount = newPosition.x - MainCamera.transform.position.x;
    MainCamera.transform.position = newPosition;
    pathManager.MoveMountains(cameraMoveAmount) 

然后,在您的 PathManager 中,使用 moveAmount 更改所有山脉的位置,以及创建下一个山脉的位置。在此之后,您应该检查是否需要显示新的山脉,而不是在 PathManager 的LateUpdate 中。这是因为您需要在检查添加新山之前移动山,如果您在不同的LateUpdate 电话中使用它们,则无法保证首先发生。

类似这样的:

// How fast the mountain layers are going to move in the direction of the camera.    
// 0.0f - will not move with the camera, mountains will slide out of frame at normal speed.
// 1.0f - will move with the camera, no movement will be visible in frame.
public float nearMountainMoveSpeed = 0.5;
public float farMountainMoveSpeed = 0.9f;

. . .

public void MoveMountains(float cameraMoveAmount) 
    float nearMountainParallaxMove = nearMountainMoveSpeed * cameraMoveAmount;
    float farMountainParallaxMove = farMountainMoveSpeed * cameraMoveAmount;

    // Move the near mountains & their next placement
    MountainNearXPosition += nearMountainParallaxMove;
    foreach (GameObject nearMountain in pooledNearMountains) 
        nearMountain.transform.position = nearMountain.transform.position + new Vector3(nearMountainParallaxMove,0f,0f);
        

    // Check for new Near Mountain
    if (lastMountainNear != null && GamePlayCameraManager.Instance.MainCamera.transform.position.x > lastMountainNear.transform.position.x) 
        this.GenerateNearMountain();
    

    // Move the far mountains & their next placement
    MountainFarXPosition += farMountainParallaxMove;
    foreach (GameObject farMountain in pooledFarMountains) 
        farMountain.transform.position = farMountain.transform.position + new Vector3(farMountainParallaxMove,0f,0f);
    

    // Check for new Far Mountain
    if (lastMountainFar != null && GamePlayCameraManager.Instance.MainCamera.transform.position.x > lastMountainFar.transform.position.x) 
        this.GenerateFarMountain();
    

顺便说一句,如果您最终更改了代码并拥有一个游戏对象,其中所有 farMountains 作为子对象,一个将所有 nearMountains 作为子对象,那么您可以只移动这些父游戏对象的变换,而不是循环穿过每一座山。当然,您需要移动它的数量是相同的。

【讨论】:

非常感谢您的详细回答,但相机管理器的最后一行给出了错误“访问非静态成员 `PathManager.MoveMountains(float)”需要对象引用” 它是小写的pathManager,因为它是对您的PathManager 实例的引用。您必须将其添加到您的GamePlayCameraManager

以上是关于如何为在播放模式下实例化并在 Unity 3d 中使用相机位置重新创建的对象添加视差的主要内容,如果未能解决你的问题,请参考以下文章

如何为 Unity3D 编写线程安全的 C# 代码?

Unity3D 门打开/关闭错误

将 Rider 与 Unity 一起使用时如何为播放按钮分配快捷方式?

IsaacSim Unity3D - 播放模式入门

unity3d 怎么用脚本控制播放制定音乐文件

unity3d 如何用GUI按钮播放动画脚本怎么写