如何生成游戏对象,然后在它们停止时重新生成它们
How to generate GameObjects, then respawn them when they are stopped
我正在编写一个在随机位置实例化云(我创建的预制件)的系统。当它们生成时,它们会通过 Vector2.MoveTowards 移动到一个地点。我想做的是检查他们是否停止了。如果他们停止了,创建新的。
我的系统:
脚本 1(程序云(我知道它们不是程序创建的,但我开始将脚本命名为这个,因为这是我想要在长 运行 中实现的目标)):
- 一个 public GameObject 数组,我在其中存储我创建的预制件,这些预制件在脚本中实例化。
- 一个 Vector3(必须使用 Vector3 而不是 2,因为我使用 Random.Range)这是起始位置之一(我总共有 6 个起始位置。)
- 起初我使用 Start 函数中的 InvokedRepeating 来随机实例化,但我放弃了它并决定根据云是否已经生成来调用我的生成方法。 (我可以尝试使用 IEnumerator 的协程,但我不知道这是否能达到目的)
脚本 2 (MoveClouds):
- 在开始函数中我定义了三个结束位置,它们是Vector3。
这是我开始挣扎的地方。我首先尝试使用 .transform.position = Vector3.MoveTowards()。但我这里的问题是检查云是否已经停止。我试过 hasChanged,但没有用。因此,经过大量谷歌搜索并尝试使其工作后,我决定将 Rigidbody2D 附加到云中,因为我认为我可以检查 velocity.magnitude == 0,然后它们就会停止。我还应用了 rb.velocity 和 rb.addforce,因为有实际的力量来检查那个力量是否已经停止并且应该产生一个新的力量。我不想使用 RB,因为它们不会与任何物理相关,它们只是从一个随机点移动到另一个特定点,然后蒸发,当它们蒸发时,会产生一个新的。
我知道它很长 post,但我非常感谢您的帮助!我已经在 Unity 中工作了 3 个多月,所以我对此还是很陌生。
我的代码:
脚本 1
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ProceduralClouds : MonoBehaviour
{
public GameObject[] clouds;
Vector3 startPos1, startPos2, startPos3, startPos4, startPos5, startPos6;
[HideInInspector] public GameObject cloud1, cloud2, cloud3, cloud4, cloud5, cloud6;
public bool cloud1Spawned, cloud2Spawned, cloud3Spawned, cloud4Spawned, cloud5Spawned, cloud6Spawned;
private void Start()
{
/*InvokeRepeating(nameof(SpawnCloud1), 0, 20);
InvokeRepeating(nameof(SpawnCloud2), 1, 22);
InvokeRepeating(nameof(SpawnCloud3), 3, 25);
InvokeRepeating(nameof(SpawnCloud4), 0, 18);
InvokeRepeating(nameof(SpawnCloud5), 2, 20);
InvokeRepeating(nameof(SpawnCloud6), 5, 21); */
}
private void Update()
{
startPos1 = new Vector3(Random.Range(15, 25), Random.Range(0, 10), 0);
startPos2 = new Vector3(Random.Range(15, 25), Random.Range(0, 10), 0);
startPos3 = new Vector3(Random.Range(15, 25), Random.Range(0, 10), 0);
startPos4 = new Vector3(Random.Range(15, 25), Random.Range(0, 10), 0);
startPos5 = new Vector3(Random.Range(15, 25), Random.Range(0, 10), 0);
startPos6 = new Vector3(Random.Range(15, 25), Random.Range(0, 10), 0);
// test prints:
print("Cloud 1 spawned: " + cloud1Spawned);
SpawnCloud1();
SpawnCloud2();
SpawnCloud3();
SpawnCloud4();
SpawnCloud5();
SpawnCloud6();
}
private void SpawnCloud1()
{
if (!cloud1Spawned)
{
cloud1 = Instantiate(clouds[Random.Range(0, clouds.Length)], startPos1, Quaternion.identity);
cloud1Spawned = true;
}
}
private void SpawnCloud2()
{
if (!cloud2Spawned)
{
cloud2Spawned = true;
cloud2 = Instantiate(clouds[Random.Range(0, clouds.Length)], startPos2, Quaternion.identity);
}
}
private void SpawnCloud3()
{
if (!cloud3Spawned)
{
cloud3 = Instantiate(clouds[Random.Range(0, clouds.Length)], startPos3, Quaternion.identity);
cloud3Spawned = true;
}
}
private void SpawnCloud4()
{
if (!cloud4Spawned)
{
cloud4 = Instantiate(clouds[Random.Range(0, clouds.Length)], startPos4, Quaternion.identity);
cloud4Spawned = true;
}
}
private void SpawnCloud5()
{
if (!cloud5Spawned)
{
cloud5 = Instantiate(clouds[Random.Range(0, clouds.Length)], startPos5, Quaternion.identity);
cloud5Spawned = true;
}
}
private void SpawnCloud6()
{
if (!cloud6Spawned)
{
cloud6 = Instantiate(clouds[Random.Range(0, clouds.Length)], startPos6, Quaternion.identity);
cloud6Spawned = true;
}
}
}
脚本 2:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveClouds : MonoBehaviour
{
public float step;
private ProceduralClouds proCloudsScript;
private GameObject cloud1, cloud2, cloud3, cloud4, cloud5, cloud6;
private Vector3 endPosBottom, endPosMiddle, endPosTop;
private void Start()
{
proCloudsScript = GameObject.Find("ScriptHandler").GetComponent<ProceduralClouds>();
endPosBottom = new Vector3(-26, 8, 0);
endPosMiddle = new Vector3(-26, 10, 0);
endPosTop = new Vector3(-26, 12, 0);
}
private void Update()
{
cloud1 = proCloudsScript.cloud1;
cloud2 = proCloudsScript.cloud2;
cloud3 = proCloudsScript.cloud3;
cloud4 = proCloudsScript.cloud4;
cloud5 = proCloudsScript.cloud5;
cloud6 = proCloudsScript.cloud6;
float step = this.step * Time.deltaTime;
/* cloud1.transform.position = Vector3.MoveTowards(cloud1.transform.position, endPosBottom, step);
cloud2.transform.position = Vector3.MoveTowards(cloud2.transform.position, endPosTop, step);
cloud3.transform.position = Vector3.MoveTowards(cloud3.transform.position, endPosMiddle, step);
cloud4.transform.position = Vector3.MoveTowards(cloud4.transform.position, endPosTop, step);
cloud5.transform.position = Vector3.MoveTowards(cloud5.transform.position, endPosBottom, step);
cloud6.transform.position = Vector3.MoveTowards(cloud6.transform.position, endPosMiddle, step);*/
cloud1.GetComponent<Rigidbody2D>().velocity = Vector2.MoveTowards(cloud1.transform.position,
endPosBottom, step);
cloud2.GetComponent<Rigidbody2D>().velocity = Vector2.MoveTowards(cloud2.transform.position,
endPosMiddle, step);
cloud3.GetComponent<Rigidbody2D>().velocity = Vector2.MoveTowards(cloud3.transform.position,
endPosTop, step);
cloud4.GetComponent<Rigidbody2D>().velocity = Vector2.MoveTowards(cloud4.transform.position,
endPosTop, step);
cloud5.GetComponent<Rigidbody2D>().velocity = Vector2.MoveTowards(cloud5.transform.position,
endPosBottom, step);
cloud6.GetComponent<Rigidbody2D>().velocity = Vector2.MoveTowards(cloud6.transform.position,
endPosMiddle, step);
if (cloud1.GetComponent<Rigidbody2D>().velocity.magnitude == 0 )
{
print("Cloud 1 is still");
proCloudsScript.cloud1Spawned = false;
print(cloud1.GetComponent<Rigidbody2D>().velocity.magnitude);
}
if (cloud2.GetComponent<Rigidbody2D>().velocity.magnitude == 0)
{
print("Cloud 2 is still");
proCloudsScript.cloud2Spawned = false;
print(cloud2.GetComponent<Rigidbody2D>().velocity.magnitude);
}
if (cloud3.GetComponent<Rigidbody2D>().velocity.magnitude == 0)
{
print("Cloud 3 is still");
proCloudsScript.cloud3Spawned = false;
print(cloud3.GetComponent<Rigidbody2D>().velocity.magnitude);
}
if (cloud4.GetComponent<Rigidbody2D>().velocity.magnitude == 0)
{
print("Cloud 4 is still");
proCloudsScript.cloud4Spawned = false;
print(cloud4.GetComponent<Rigidbody2D>().velocity.magnitude);
}
if (cloud5.GetComponent<Rigidbody2D>().velocity.magnitude == 0)
{
print("Cloud 5 is still");
proCloudsScript.cloud5Spawned = false;
print(cloud5.GetComponent<Rigidbody2D>().velocity.magnitude);
}
if (cloud6.GetComponent<Rigidbody2D>().velocity.magnitude == 0)
{
print("Cloud 6 is still");
proCloudsScript.cloud6Spawned = false;
print(cloud6.GetComponent<Rigidbody2D>().velocity.magnitude);
}
}
}
我在你的代码中看到了很多小问题!
我会从 Vector3
的用法开始.. 如果你真的想要 Vector2
然后使用它 ;)
一遍又一遍地实现相同的功能只是为了有不同的数字,这真的很糟糕!尝试将所有这些合并到一个方法中。这是 a) 更好的维护和 b) 可扩展性!
您正在传递使用
生成的位置
Vector2.MoveTowards(cloud1.transform.position, endPosBottom, step);
到速度 -> 没有意义。
尽管它在新版本中得到了很大改进,但多次使用 GetComponent
over ad 并且 every frame 效率极低。
每帧生成新的随机位置,然后在大多数情况下将它们扔掉,因为如果云仍在移动,您就不会生成它,这又是非常效率低下。
所以我会这样做
// Responsible for creating and initializing cloud instances
public class ProceduralClouds : MonoBehaviour
{
// As before here assign your prefabs
// CloudMove is a dedicated script that will go onto your cloud prefabs
// See next code snippet
public CloudMove[] clouds;
// How many clouds should be spawned?
public int amountOfClouds = 6;
// Configure your possible target position in the Inspector
public Vector2[] targetPositions = { new Vector3(-26, 8, 0), new Vector3(-26, 10, 0), new Vector3(-26, 12, 0) };
// This will keep track which target position chose next
// (could make it random as well)
private int currentTargetIndex;
private void Start()
{
// Spawn the first "wave" of clouds
for(var i = 0; i < amountOfClouds; i++)
{
SpawnCloud();
}
}
private void SpawnCloud()
{
// pick a random start position
var startPos = new Vector2(Random.Range(15, 25), Random.Range(0, 10));
// get the next target position
var targetPos = targetPositions [currentTargetIndex];
// Increase the index, wrap around if reaching end of array
currentTargetIndex = (currentTargetIndex + 1) % targetPositions.Length;
// instantiate the cloud
var cloud = Instantiate(clouds[Random.Range(0, clouds.Length)], startPos, Quaternion.identity);
// assign its target position
// Could also pick a random speed here
cloud.targetPosition = targetPos;
// Assign a callback to an event we will implement
// This is way better than poll check stuff in Update
cloud.OnReachedTarget += SpawnCloud;
}
}
然后另一个脚本直接在您的云预制件上:
// Responsible for moving one cloud instance
public class CloudMove : MonoBehaviour
{
// Basically equals your step
// But this way the clouds could even have individual speed values
public float speed = 1;
// Will be assigned by the spawner script
public Vector2 targetPosition;
// Whoever wants can be listening here
public event Action OnReachedTarget;
private void Update ()
{
// Move towards the target position with given speed
transform.position = Vector2.MoveTowards(transform.position, targetPosition, speed * Time.deltaTime);
// Either use this check with a precision of 0.00001
if((Vector2)transform.position == targetPosition)
// Or alternatively if you need a more exact precision
//if(Mathf.Approximately(Vector2.Distance(transform.position, targetPosition), 0))
{
// Invoke the event so whoever is listening is informed
OnReachedTarget?.Invoke();
// You might be interested in destroying this cloud once it reached its target
//Destroy(gameObject):
}
}
}
我正在编写一个在随机位置实例化云(我创建的预制件)的系统。当它们生成时,它们会通过 Vector2.MoveTowards 移动到一个地点。我想做的是检查他们是否停止了。如果他们停止了,创建新的。
我的系统:
脚本 1(程序云(我知道它们不是程序创建的,但我开始将脚本命名为这个,因为这是我想要在长 运行 中实现的目标)):
- 一个 public GameObject 数组,我在其中存储我创建的预制件,这些预制件在脚本中实例化。
- 一个 Vector3(必须使用 Vector3 而不是 2,因为我使用 Random.Range)这是起始位置之一(我总共有 6 个起始位置。)
- 起初我使用 Start 函数中的 InvokedRepeating 来随机实例化,但我放弃了它并决定根据云是否已经生成来调用我的生成方法。 (我可以尝试使用 IEnumerator 的协程,但我不知道这是否能达到目的)
脚本 2 (MoveClouds):
- 在开始函数中我定义了三个结束位置,它们是Vector3。
这是我开始挣扎的地方。我首先尝试使用 .transform.position = Vector3.MoveTowards()。但我这里的问题是检查云是否已经停止。我试过 hasChanged,但没有用。因此,经过大量谷歌搜索并尝试使其工作后,我决定将 Rigidbody2D 附加到云中,因为我认为我可以检查 velocity.magnitude == 0,然后它们就会停止。我还应用了 rb.velocity 和 rb.addforce,因为有实际的力量来检查那个力量是否已经停止并且应该产生一个新的力量。我不想使用 RB,因为它们不会与任何物理相关,它们只是从一个随机点移动到另一个特定点,然后蒸发,当它们蒸发时,会产生一个新的。
我知道它很长 post,但我非常感谢您的帮助!我已经在 Unity 中工作了 3 个多月,所以我对此还是很陌生。
我的代码: 脚本 1
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ProceduralClouds : MonoBehaviour
{
public GameObject[] clouds;
Vector3 startPos1, startPos2, startPos3, startPos4, startPos5, startPos6;
[HideInInspector] public GameObject cloud1, cloud2, cloud3, cloud4, cloud5, cloud6;
public bool cloud1Spawned, cloud2Spawned, cloud3Spawned, cloud4Spawned, cloud5Spawned, cloud6Spawned;
private void Start()
{
/*InvokeRepeating(nameof(SpawnCloud1), 0, 20);
InvokeRepeating(nameof(SpawnCloud2), 1, 22);
InvokeRepeating(nameof(SpawnCloud3), 3, 25);
InvokeRepeating(nameof(SpawnCloud4), 0, 18);
InvokeRepeating(nameof(SpawnCloud5), 2, 20);
InvokeRepeating(nameof(SpawnCloud6), 5, 21); */
}
private void Update()
{
startPos1 = new Vector3(Random.Range(15, 25), Random.Range(0, 10), 0);
startPos2 = new Vector3(Random.Range(15, 25), Random.Range(0, 10), 0);
startPos3 = new Vector3(Random.Range(15, 25), Random.Range(0, 10), 0);
startPos4 = new Vector3(Random.Range(15, 25), Random.Range(0, 10), 0);
startPos5 = new Vector3(Random.Range(15, 25), Random.Range(0, 10), 0);
startPos6 = new Vector3(Random.Range(15, 25), Random.Range(0, 10), 0);
// test prints:
print("Cloud 1 spawned: " + cloud1Spawned);
SpawnCloud1();
SpawnCloud2();
SpawnCloud3();
SpawnCloud4();
SpawnCloud5();
SpawnCloud6();
}
private void SpawnCloud1()
{
if (!cloud1Spawned)
{
cloud1 = Instantiate(clouds[Random.Range(0, clouds.Length)], startPos1, Quaternion.identity);
cloud1Spawned = true;
}
}
private void SpawnCloud2()
{
if (!cloud2Spawned)
{
cloud2Spawned = true;
cloud2 = Instantiate(clouds[Random.Range(0, clouds.Length)], startPos2, Quaternion.identity);
}
}
private void SpawnCloud3()
{
if (!cloud3Spawned)
{
cloud3 = Instantiate(clouds[Random.Range(0, clouds.Length)], startPos3, Quaternion.identity);
cloud3Spawned = true;
}
}
private void SpawnCloud4()
{
if (!cloud4Spawned)
{
cloud4 = Instantiate(clouds[Random.Range(0, clouds.Length)], startPos4, Quaternion.identity);
cloud4Spawned = true;
}
}
private void SpawnCloud5()
{
if (!cloud5Spawned)
{
cloud5 = Instantiate(clouds[Random.Range(0, clouds.Length)], startPos5, Quaternion.identity);
cloud5Spawned = true;
}
}
private void SpawnCloud6()
{
if (!cloud6Spawned)
{
cloud6 = Instantiate(clouds[Random.Range(0, clouds.Length)], startPos6, Quaternion.identity);
cloud6Spawned = true;
}
}
}
脚本 2:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveClouds : MonoBehaviour
{
public float step;
private ProceduralClouds proCloudsScript;
private GameObject cloud1, cloud2, cloud3, cloud4, cloud5, cloud6;
private Vector3 endPosBottom, endPosMiddle, endPosTop;
private void Start()
{
proCloudsScript = GameObject.Find("ScriptHandler").GetComponent<ProceduralClouds>();
endPosBottom = new Vector3(-26, 8, 0);
endPosMiddle = new Vector3(-26, 10, 0);
endPosTop = new Vector3(-26, 12, 0);
}
private void Update()
{
cloud1 = proCloudsScript.cloud1;
cloud2 = proCloudsScript.cloud2;
cloud3 = proCloudsScript.cloud3;
cloud4 = proCloudsScript.cloud4;
cloud5 = proCloudsScript.cloud5;
cloud6 = proCloudsScript.cloud6;
float step = this.step * Time.deltaTime;
/* cloud1.transform.position = Vector3.MoveTowards(cloud1.transform.position, endPosBottom, step);
cloud2.transform.position = Vector3.MoveTowards(cloud2.transform.position, endPosTop, step);
cloud3.transform.position = Vector3.MoveTowards(cloud3.transform.position, endPosMiddle, step);
cloud4.transform.position = Vector3.MoveTowards(cloud4.transform.position, endPosTop, step);
cloud5.transform.position = Vector3.MoveTowards(cloud5.transform.position, endPosBottom, step);
cloud6.transform.position = Vector3.MoveTowards(cloud6.transform.position, endPosMiddle, step);*/
cloud1.GetComponent<Rigidbody2D>().velocity = Vector2.MoveTowards(cloud1.transform.position,
endPosBottom, step);
cloud2.GetComponent<Rigidbody2D>().velocity = Vector2.MoveTowards(cloud2.transform.position,
endPosMiddle, step);
cloud3.GetComponent<Rigidbody2D>().velocity = Vector2.MoveTowards(cloud3.transform.position,
endPosTop, step);
cloud4.GetComponent<Rigidbody2D>().velocity = Vector2.MoveTowards(cloud4.transform.position,
endPosTop, step);
cloud5.GetComponent<Rigidbody2D>().velocity = Vector2.MoveTowards(cloud5.transform.position,
endPosBottom, step);
cloud6.GetComponent<Rigidbody2D>().velocity = Vector2.MoveTowards(cloud6.transform.position,
endPosMiddle, step);
if (cloud1.GetComponent<Rigidbody2D>().velocity.magnitude == 0 )
{
print("Cloud 1 is still");
proCloudsScript.cloud1Spawned = false;
print(cloud1.GetComponent<Rigidbody2D>().velocity.magnitude);
}
if (cloud2.GetComponent<Rigidbody2D>().velocity.magnitude == 0)
{
print("Cloud 2 is still");
proCloudsScript.cloud2Spawned = false;
print(cloud2.GetComponent<Rigidbody2D>().velocity.magnitude);
}
if (cloud3.GetComponent<Rigidbody2D>().velocity.magnitude == 0)
{
print("Cloud 3 is still");
proCloudsScript.cloud3Spawned = false;
print(cloud3.GetComponent<Rigidbody2D>().velocity.magnitude);
}
if (cloud4.GetComponent<Rigidbody2D>().velocity.magnitude == 0)
{
print("Cloud 4 is still");
proCloudsScript.cloud4Spawned = false;
print(cloud4.GetComponent<Rigidbody2D>().velocity.magnitude);
}
if (cloud5.GetComponent<Rigidbody2D>().velocity.magnitude == 0)
{
print("Cloud 5 is still");
proCloudsScript.cloud5Spawned = false;
print(cloud5.GetComponent<Rigidbody2D>().velocity.magnitude);
}
if (cloud6.GetComponent<Rigidbody2D>().velocity.magnitude == 0)
{
print("Cloud 6 is still");
proCloudsScript.cloud6Spawned = false;
print(cloud6.GetComponent<Rigidbody2D>().velocity.magnitude);
}
}
}
我在你的代码中看到了很多小问题!
我会从
Vector3
的用法开始.. 如果你真的想要Vector2
然后使用它 ;)一遍又一遍地实现相同的功能只是为了有不同的数字,这真的很糟糕!尝试将所有这些合并到一个方法中。这是 a) 更好的维护和 b) 可扩展性!
您正在传递使用
生成的位置Vector2.MoveTowards(cloud1.transform.position, endPosBottom, step);
到速度 -> 没有意义。
尽管它在新版本中得到了很大改进,但多次使用
GetComponent
over ad 并且 every frame 效率极低。每帧生成新的随机位置,然后在大多数情况下将它们扔掉,因为如果云仍在移动,您就不会生成它,这又是非常效率低下。
所以我会这样做
// Responsible for creating and initializing cloud instances
public class ProceduralClouds : MonoBehaviour
{
// As before here assign your prefabs
// CloudMove is a dedicated script that will go onto your cloud prefabs
// See next code snippet
public CloudMove[] clouds;
// How many clouds should be spawned?
public int amountOfClouds = 6;
// Configure your possible target position in the Inspector
public Vector2[] targetPositions = { new Vector3(-26, 8, 0), new Vector3(-26, 10, 0), new Vector3(-26, 12, 0) };
// This will keep track which target position chose next
// (could make it random as well)
private int currentTargetIndex;
private void Start()
{
// Spawn the first "wave" of clouds
for(var i = 0; i < amountOfClouds; i++)
{
SpawnCloud();
}
}
private void SpawnCloud()
{
// pick a random start position
var startPos = new Vector2(Random.Range(15, 25), Random.Range(0, 10));
// get the next target position
var targetPos = targetPositions [currentTargetIndex];
// Increase the index, wrap around if reaching end of array
currentTargetIndex = (currentTargetIndex + 1) % targetPositions.Length;
// instantiate the cloud
var cloud = Instantiate(clouds[Random.Range(0, clouds.Length)], startPos, Quaternion.identity);
// assign its target position
// Could also pick a random speed here
cloud.targetPosition = targetPos;
// Assign a callback to an event we will implement
// This is way better than poll check stuff in Update
cloud.OnReachedTarget += SpawnCloud;
}
}
然后另一个脚本直接在您的云预制件上:
// Responsible for moving one cloud instance
public class CloudMove : MonoBehaviour
{
// Basically equals your step
// But this way the clouds could even have individual speed values
public float speed = 1;
// Will be assigned by the spawner script
public Vector2 targetPosition;
// Whoever wants can be listening here
public event Action OnReachedTarget;
private void Update ()
{
// Move towards the target position with given speed
transform.position = Vector2.MoveTowards(transform.position, targetPosition, speed * Time.deltaTime);
// Either use this check with a precision of 0.00001
if((Vector2)transform.position == targetPosition)
// Or alternatively if you need a more exact precision
//if(Mathf.Approximately(Vector2.Distance(transform.position, targetPosition), 0))
{
// Invoke the event so whoever is listening is informed
OnReachedTarget?.Invoke();
// You might be interested in destroying this cloud once it reached its target
//Destroy(gameObject):
}
}
}