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中了,你还可以改变障碍物的位置,继续生成更多套方案,到时候游戏运行的时候就随机取一套方案执行了。

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

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
这里提供一种简易的Unity-2D随机生成地图障碍物的方法: 1. 创建一个空物体,命名为MapGenerator,将其挂载一个脚本MapGenerator.cs。 2. 在脚本定义一些公共变量,如地图大小、障碍物数量、障碍物大小等。 3. 在Start()方法,使用循环生成地图障碍物。可以使用随机数来生成地图障碍物的位置和大小。 4. 生成地图时,可以使用Tilemap组件来创建砖块地图。可以使用Tile Palette工具来创建不同的砖块,并在脚本随机选择一些砖块来生成地图。 5. 生成障碍物时,可以使用SpriteRenderer组件来创建障碍物。可以使用多个Sprite来创建不同的障碍物,并在脚本随机选择一些Sprite来生成障碍物。 6. 最后,将生成地图障碍物放置在MapGenerator物体下,并运行游戏即可。 下面是MapGenerator.cs的代码示例: ``` using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Tilemaps; public class MapGenerator : MonoBehaviour { public int mapWidth = 100; public int mapHeight = 100; public int obstacleCount = 20; public float obstacleSize = 1f; public Tilemap tilemap; public TileBase[] tiles; public Sprite[] obstacles; // Start is called before the first frame update void Start() { GenerateMap(); GenerateObstacles(); } void GenerateMap() { for (int x = 0; x < mapWidth; x++) { for (int y = 0; y < mapHeight; y++) { tilemap.SetTile(new Vector3Int(x, y, 0), tiles[Random.Range(0, tiles.Length)]); } } } void GenerateObstacles() { for (int i = 0; i < obstacleCount; i++) { GameObject obstacle = new GameObject("Obstacle"); obstacle.transform.parent = transform; SpriteRenderer sr = obstacle.AddComponent<SpriteRenderer>(); sr.sprite = obstacles[Random.Range(0, obstacles.Length)]; float size = Random.Range(obstacleSize / 2f, obstacleSize); obstacle.transform.localScale = new Vector3(size, size, 1f); float x = Random.Range(0f, mapWidth); float y = Random.Range(0f, mapHeight); obstacle.transform.position = new Vector3(x, y, 0f); } } } ``` 在这个示例,我们使用了Tilemap组件来生成地图,并使用了SpriteRenderer组件来生成障碍物。你可以根据自己的需求来修改代码。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值