Unity中生成无缝衔接的地图,并用编辑器扩展轻松生成几套障碍物方案

无缝衔接的地图

我现在有四个地图,名字分别为Pattern_1、Pattern_2、Pattern_3、Pattern_4,然后计算地图的长度,我的是160,每次进行无缝衔接的时候,只需将要生成的地图在当前地图的基础上加上160即可进行无缝衔接了,然后每次都是随机生成一个地图进行衔接的。
代码如下:

由于地图是无缝衔接的,要经常生成地图,然后销毁地图的,但这样做,性能不太好,所以下面也用到了对象池技术,包括障碍物的生成与销毁也用到了对象池技术,这也相当于是对象池技术的一个应用了,具体的对象池技术的代码实现,请移步去https://blog.csdn.net/weixin_43839583/article/details/103405831学习。

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

public class RoadChange : MonoBehaviour
{
    private GameObject roadNow;//当前的路
    private GameObject roadNext;//下一条路
    private GameObject parent;//游戏第一次运行时,第一条路的游戏物体
    // Start is called before the first frame update
    void Start()
    {
        if(parent==null)
        {
            parent = new GameObject();
            parent.transform.position = Vector3.zero;
            parent.name = "Road";
        }
        roadNow = Game.Instance.objectPool.Spawn("Pattern_1", parent.transform);
        roadNext = Game.Instance.objectPool.Spawn("Pattern_2", parent.transform);
        roadNext.transform.position += new Vector3(0, 0, 160);
        AddItem(roadNow);//这是下面的添加障碍物的方法,之后会用到
        AddItem(roadNext);
    }

    private void OnTriggerEnter(Collider other)//当主角碰到了地图上的碰撞体,就开始生成新地图
    {
        if(other.gameObject.tag==Tag.road)
        {
            //回收
            Game.Instance.objectPool.UnSpawn(other.gameObject);
            //创建新的跑道
            SpawnNextRoad();
        }
    }
    /// <summary>
    /// 创建新的跑道,即生成下一条路的方法
    /// </summary>
    private void SpawnNextRoad()
    {
        int i = Random.Range(1, 5);//四条路随机取一条
        roadNow = roadNext;//原本的下一条跑道变成当前跑道
        //生成新的跑道
        roadNext = Game.Instance.objectPool.Spawn("Pattern_" + i.ToString(), parent.transform);
        roadNext.transform.position = roadNow.transform.position + new Vector3(0, 0, 160);//新跑道是原跑道的基础上加160
        AddItem(roadNext);//在新跑道上添加障碍物
    }

    /// <summary>
    /// 生成障碍物
    /// </summary>
    /// <param name="obj"></param>
    public void AddItem(GameObject obj)
    {
        var itemChild = obj.transform.Find("Item");
        if(itemChild!=null)
        {
            var patternManager = PatternManager.Instance;
            if(patternManager!=null&&patternManager.patterns!=null&&patternManager.patterns.Count>0)
            {
                //随机取一个方案
                var pattern = patternManager.patterns[Random.Range(0, patternManager.patterns.Count)];
                if(pattern!=null&&pattern.patternItems!=null&&pattern.patternItems.Count>0)
                {
                    foreach (var itemList in pattern.patternItems)
                    {
                        GameObject go = Game.Instance.objectPool.Spawn(itemList.prefabName, itemChild);
                        go.transform.parent = itemChild;
                        go.transform.localPosition = itemList.pos;
                    }
                }
            }
        }
    }
}

上面有个 public void AddItem(GameObject obj)的生成障碍物的方法,其中的PatternManager类的代码实现如下:

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

public class PatternManager : MonoSingleton<PatternManager>
{
    public List<Pattern> patterns = new List<Pattern>();//很多套生成障碍物的方案
    
}
//一个游戏物体的信息
[Serializable]
public class PatternItem
{
    public string prefabName;
    public Vector3 pos;
}
//一套方案
[Serializable]
public class Pattern
{
    public List<PatternItem> patternItems = new List<PatternItem>();
}

在Unity中先新建一个PatternManager 的空物体,然后挂载这个同名的脚本,然后在这个脚本中手动赋值,添加每个障碍物的名字和位置。
需要注意的是,在地图的Prefab中添加一个名为Item的子物体,然后以后生成的障碍物都放在这个Item下,调用上面的AddItem(GameObject obj)方法就可以添加障碍物了。

编辑器扩展的妙用

在上面的操作中,可以生成无缝衔接的地图了,也能随机取一套障碍物进行生成,但是障碍物的名字和位置必须要我们手动赋值,障碍物比较少的时候还好说,当一套方案中有五六十个障碍物,然后你要摆十几套方案时,一个一个的赋值是非常耗时间的,效率非常低,所以我们使用编辑器扩展功能,非常的方便。首先要新建一个名为Editor的文件夹,然后在Editor中新建一个脚本,我将它取名为SpawnManager。SpawnManager必须继承自Editor.
具体的实现代码如下:

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

public class SpawnManager : Editor
{
    [MenuItem("Tools/Click me!")]
    static void PatternSystem()
    {
        GameObject spawnManager = GameObject.Find("PatternManager");
        if(spawnManager!=null)
        {
            var patternManager = spawnManager.GetComponent<PatternManager>();
            if(Selection.gameObjects.Length==1)
            {
                var item = Selection.gameObjects[0].transform.Find("Item");
                if(item!=null)
                {
                    Pattern pattern = new Pattern();
                    foreach (var child in item)
                    {
                        Transform childTrans = child as Transform;
                        if (childTrans != null)
                        {
                            //找到它对应的预制体
                            var prefab = UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(childTrans.gameObject);
                            if(prefab!=null)
                            {
                                PatternItem patternItem = new PatternItem
                                {
                                    pos = childTrans.localPosition,
                                    prefabName = prefab.name
                                };
                                pattern.patternItems.Add(patternItem);
                            }
                        }
                    }
                    patternManager.patterns.Add(pattern);
                }
            }
        }
    }
}

[MenuItem(“Tools/Click me!”)]表示在编辑器上添加了Tools/Click me!的按钮,点击的时候,执行它下面的静态方法。即执行PatternSystem()方法。
if(Selection.gameObjects.Length==1)表示在编辑器中选中的游戏物体个数是1个的时候执行下面的代码。
UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(childTrans.gameObject)是根据Hierarchy面板上的物体找到它对应的预制体。为什么要找预制体?因为如果Item下有很多同名的物体,比如coin,那个下一个就是coin(1)了,那么名字就对不上了,因为它的名字就只是coin而已,而coin和coin(1)的预制体对应的名字都是coin,所以要取得预制体。然后将名字写入新建的patternItem,而位置的话,取原本的位置,不能取预制体的位置,因为预制体的位置都是一样的,我们不能将所有的障碍物都生成到同一位置吧。最后由patternManager.patterns.Add(pattern)将一套方案添加进去。
需要注意的是,我们要事先在地图中的Item下摆放好每一个障碍物的位置,摆完后,点击这个Item的父物体,即整个地图,然后点击Tools/Click me!就自动把地图上的障碍物的名字和位置信息添加到PatternManager中了,你还可以改变障碍物的位置,继续生成更多套方案,到时候游戏运行的时候就随机取一套方案执行了。

这就是编辑器扩展的妙用了。

发布了15 篇原创文章 · 获赞 0 · 访问量 252

猜你喜欢

转载自blog.csdn.net/weixin_43839583/article/details/103452814