Endless Runner "Treadmill" 与对象池的差距
Gaps in Endless Runner "Treadmill" with Object Pooling
我正在开发一款 3D 无尽跑酷游戏,其中玩家静止不动,background/obstacles 在他们周围移动。我正在使用对象池。
背景由大型 "City Block" 对象的多个变体组成,其中包含地面的 3D 平面立方体对象。每个 City Block 对象在街道上都有不同种类的障碍物,但这些对象是父对象 "CityBlock" 的子对象,因此会随之移动。这些城市街区在屏幕外彼此重叠,并且有两个是默认的起始街区,排成一行并放置在屏幕中。激活后,它们有一个脚本,可以简单地沿 x 轴移动它们。当他们越过玩家到达某个点时,他们会重置回到屏幕外的起始位置。
我创建了一个游戏对象列表,并在编辑器中用场景中的城市街区填充它。然后将列表随机化,"activates" 索引为 0 的那个,然后递增并继续激活下一个。
每次到达列表末尾时,我都会重新随机化,然后再次循环。这样,游戏应该是真正随机的,而不是每次迭代都在相同的对象循环中循环。
我的问题是我经常在背景 "treadmill" 中以 "gaps" 结束,它构成了整个城市街区的大小,这是我能够解决这个问题的唯一方法问题是使用递归,如果它到达已经激活的城市街区,则再次调用该方法。这会在目标移动设备上造成性能问题,并不能完全解决问题(经过几次迭代后,差距再次出现)。
我觉得我在某个兔子洞里走得太远了,或者我的视野太狭窄了,必须有更好的方法来随机化游戏对象列表并随机激活它们。
public class CityBlockManager : MonoBehaviour {
public List<GameObject> cityBlockList = new List<GameObject>(); //List is populated in-editor, not through script
public int listSize;
public int counter; //Only made public to be seen in editor
//Use this for initialization
//On initialization, will determine the size of the list, randomize it, and active the first member of that list.
void Start () {
listSize = cityBlockList.Count - 1;
RandomizeList();
cityBlockList[0].GetComponent<CityBlockMover>().isActive = true;
}
//Given the list of any size of game objects, will randomize/shuffle it
void RandomizeList()
{
for (int i = 0; i <= listSize; i++)
{
GameObject temp = cityBlockList[i];
int randomIndex = Random.Range(i, cityBlockList.Count);
cityBlockList[i] = cityBlockList[randomIndex];
cityBlockList[randomIndex] = temp;
}
}
//Keeps track of how many members of the list have been activated, and if it reaches the full list, will randomize the list over again.
//On each call, will activate the next game object in the list.
public void ActivateNext()
{
counter++;
if (counter > listSize || cityBlockList[counter] == null)
{
counter = 0;
RandomizeList(); //Re-randomize list, start over
//Helps ensure there are no gaps in city block "spawning"
if(cityBlockList[0].GetComponent<CityBlockMover>().isActive != true)
{
cityBlockList[0].GetComponent<CityBlockMover>().isActive = true;
return;
}
else
{
ActivateNext();
return;
}
}
if (cityBlockList[counter].GetComponent<CityBlockMover>().isActive == false && cityBlockList[counter] != null)
{
cityBlockList[counter].GetComponent<CityBlockMover>().isActive = true;
}
else
{
counter++;
if (counter > listSize || !cityBlockList[counter])
{
counter = 0;
RandomizeList();
if (cityBlockList[0].GetComponent<CityBlockMover>().isActive != true)
{
cityBlockList[0].GetComponent<CityBlockMover>().isActive = true;
}
else
{
ActivateNext();
return;
}
}
}
}
}
考虑使用 2 个列表,一个活动块列表和一个非活动块列表,这样问题可能会变得更清楚。
另外,如果你只使用一个列表,RandomizeList();
在它只包含几个非活动块时会变得非常低效,它会在第一个随机给你一个非活动块之前被频繁调用地点 - 这也是使用 2 个列表的原因。
通过确保在项目设置 > 脚本执行顺序中的默认时间之前调用移动我的环境的脚本,我能够解决我的无限运行器项目发生的问题。
这是因为我跟踪道路位置并实例化新道路的脚本是运行 在我的移动环境脚本之前。当 Unity 实际执行 实例化时导致位置过时。
我正在开发一款 3D 无尽跑酷游戏,其中玩家静止不动,background/obstacles 在他们周围移动。我正在使用对象池。
背景由大型 "City Block" 对象的多个变体组成,其中包含地面的 3D 平面立方体对象。每个 City Block 对象在街道上都有不同种类的障碍物,但这些对象是父对象 "CityBlock" 的子对象,因此会随之移动。这些城市街区在屏幕外彼此重叠,并且有两个是默认的起始街区,排成一行并放置在屏幕中。激活后,它们有一个脚本,可以简单地沿 x 轴移动它们。当他们越过玩家到达某个点时,他们会重置回到屏幕外的起始位置。
我创建了一个游戏对象列表,并在编辑器中用场景中的城市街区填充它。然后将列表随机化,"activates" 索引为 0 的那个,然后递增并继续激活下一个。
每次到达列表末尾时,我都会重新随机化,然后再次循环。这样,游戏应该是真正随机的,而不是每次迭代都在相同的对象循环中循环。
我的问题是我经常在背景 "treadmill" 中以 "gaps" 结束,它构成了整个城市街区的大小,这是我能够解决这个问题的唯一方法问题是使用递归,如果它到达已经激活的城市街区,则再次调用该方法。这会在目标移动设备上造成性能问题,并不能完全解决问题(经过几次迭代后,差距再次出现)。
我觉得我在某个兔子洞里走得太远了,或者我的视野太狭窄了,必须有更好的方法来随机化游戏对象列表并随机激活它们。
public class CityBlockManager : MonoBehaviour {
public List<GameObject> cityBlockList = new List<GameObject>(); //List is populated in-editor, not through script
public int listSize;
public int counter; //Only made public to be seen in editor
//Use this for initialization
//On initialization, will determine the size of the list, randomize it, and active the first member of that list.
void Start () {
listSize = cityBlockList.Count - 1;
RandomizeList();
cityBlockList[0].GetComponent<CityBlockMover>().isActive = true;
}
//Given the list of any size of game objects, will randomize/shuffle it
void RandomizeList()
{
for (int i = 0; i <= listSize; i++)
{
GameObject temp = cityBlockList[i];
int randomIndex = Random.Range(i, cityBlockList.Count);
cityBlockList[i] = cityBlockList[randomIndex];
cityBlockList[randomIndex] = temp;
}
}
//Keeps track of how many members of the list have been activated, and if it reaches the full list, will randomize the list over again.
//On each call, will activate the next game object in the list.
public void ActivateNext()
{
counter++;
if (counter > listSize || cityBlockList[counter] == null)
{
counter = 0;
RandomizeList(); //Re-randomize list, start over
//Helps ensure there are no gaps in city block "spawning"
if(cityBlockList[0].GetComponent<CityBlockMover>().isActive != true)
{
cityBlockList[0].GetComponent<CityBlockMover>().isActive = true;
return;
}
else
{
ActivateNext();
return;
}
}
if (cityBlockList[counter].GetComponent<CityBlockMover>().isActive == false && cityBlockList[counter] != null)
{
cityBlockList[counter].GetComponent<CityBlockMover>().isActive = true;
}
else
{
counter++;
if (counter > listSize || !cityBlockList[counter])
{
counter = 0;
RandomizeList();
if (cityBlockList[0].GetComponent<CityBlockMover>().isActive != true)
{
cityBlockList[0].GetComponent<CityBlockMover>().isActive = true;
}
else
{
ActivateNext();
return;
}
}
}
}
}
考虑使用 2 个列表,一个活动块列表和一个非活动块列表,这样问题可能会变得更清楚。
另外,如果你只使用一个列表,RandomizeList();
在它只包含几个非活动块时会变得非常低效,它会在第一个随机给你一个非活动块之前被频繁调用地点 - 这也是使用 2 个列表的原因。
通过确保在项目设置 > 脚本执行顺序中的默认时间之前调用移动我的环境的脚本,我能够解决我的无限运行器项目发生的问题。
这是因为我跟踪道路位置并实例化新道路的脚本是运行 在我的移动环境脚本之前。当 Unity 实际执行 实例化时导致位置过时。