Unity柏林噪声生成地图,以及映射小地图,点击地图导航(有水有土地有装饰)

1.土地的生成 :创建空对象,挂载以下脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.UI;
using UnityEngine.UIElements;

[RequireComponent(typeof(MeshFilter), typeof(MeshCollider), typeof(MeshRenderer))]
//柏林噪声地图
public class BoLingMaps : MonoBehaviour
{
    //长
    public int x = 100;
    //款
    public int y = 100;
    //存储生成出的物品
    public List<GameObject> bodyList = new List<GameObject>();
    //水面高度
    [Range(-5,5)]public float waterHeight = 2f;
    // 植物或矿石的预制件
    public GameObject[] objectsToSpawn; 
    //要生成的物品
    public int numberOfObjects = 100;
    //存储水面上面的顶点的集合
    private List<Vector3> verticesPositions;
    VertexHelper vh;
    Mesh mesh;

    private void Awake()
    {
        vh = new VertexHelper();
        verticesPositions = new List<Vector3>();
        for (int i = 0; i < x; i++)
        {
            for (int j = 0; j < y; j++)
            {
                float rx = Random.Range(0.02f, 0.02f);
                float ry = Random.Range(0.02f, 0.02f);
                float hight = Mathf.PerlinNoise(i * 0.02f + rx, j * 0.02f + ry);
                float uvx = (float)i / (x - 1);
                float uvy = (float)j / (y - 1);
                Vector3 pos = new Vector3(i, hight*10, j);
                vh.AddVert(pos, Color.green, new Vector2(uvx, uvy));
                if (pos.y >= waterHeight)
                {
                    //存储水面上面的顶点,用来生成物品
                    verticesPositions.Add(pos);
                }
                
                if (i != x - 1 && j != y - 1)
                {
                    vh.AddTriangle(i * y + j, i * y + j + 1, (i + 1) * y + j + 1);
                    vh.AddTriangle(i * y + j, (i + 1) * y + j + 1, (i + 1) * y + j);
                }
                
            }
        }

        mesh = new Mesh();
        vh.FillMesh(mesh);
        GetComponent<MeshFilter>().mesh = mesh;

        CreateWater();
        SpawnObjects();
    }
    //绘制水面
    void CreateWater()
    {
        GameObject water = GameObject.CreatePrimitive(PrimitiveType.Plane);
        water.transform.localScale = new Vector3(x / 10f, 1, y / 10f);
        water.transform.position = new Vector3(x / 2f,waterHeight, y / 2f);
        water.AddComponent<NavMeshObstacle>().carving = true;
        water.GetComponent<Renderer>().material = new Material(Shader.Find("Standard"))
        {
            color = Color.blue
        };
    }
    //生成地图装饰
    void SpawnObjects()
    {
        for (int i = 0; i < numberOfObjects; i++)
        {
            if (verticesPositions.Count > 0)
            {
                //随机模型
                GameObject objectToSpawn = objectsToSpawn[Random.Range(0, objectsToSpawn.Length)];
                objectToSpawn.transform.localScale = Vector3.one * 3;
                //随机位置
                Vector3 randomVertex = verticesPositions[Random.Range(0, verticesPositions.Count)];
                GameObject obj = Instantiate(objectToSpawn, randomVertex, Quaternion.identity);
                bodyList.Add(obj);
            }
        }
    }
}

如图所示:框选处放想生成的预制体,空对象挂载NavMeshSourceTag

2.角色的创建:如下图,挂载LocalNavMeshBuilder脚本,CubeMove是移动脚本(主要是射线点击地面移动)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static UnityEditor.Experimental.GraphView.GraphView;
using UnityEngine.AI;

public class CubeMove : MonoBehaviour
{
    public Ray ray;//声明射线
    public NavMeshAgent nav;//获取NavMeshAgent

    // Start is called before the first frame update
    void Start()
    {
        nav = this.GetComponent<NavMeshAgent>();
    }

    // Update is called once per frame
    void Update()
    {
        射线点击地面移动
        //if (Input.GetKeyDown(KeyCode.Mouse0)) //如果鼠标左键点击
        //{
        //    ray = Camera.main.ScreenPointToRay(Input.mousePosition);//射线从鼠标在屏幕坐标中发射
        //    RaycastHit hit;
        //    //存储射线对象内的投射命中点的信息到RaycastHit 
        //    if (Physics.Raycast(ray, out hit))
        //    {
        //        Vector3 points = hit.point;
        //        //transform.LookAt(points);
        //        //让导航对像在移动时始终面向导航坐标位置
        //        nav.SetDestination(points);
        //        //利用导航到指定坐标点位置
        //    }
        //}
    }
    private void OnTriggerEnter(Collider other)
    {
        //判断碰撞到的物品以便后续逻辑
        if(other.tag == "Body")
        {
            print(other.gameObject.name);
        }
    }
}

注意:LocalNavMeshBuilder和NavMeshSourceTag都是动态烘焙地形包的脚本

3.两种小地图的制作:

(1).左侧:人物Image始终在中间,Slider控制小地图Image缩放,地图Image移动

(2).右侧:小地图Image不变,人物Image移动(注意挂载脚本的Image的Pivot设置为(0,0))

如图是UI搭建:

小地图一:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.EventSystems;
using UnityEngine.UI;

//Image有Mask,两个Image子类,一个挂脚本,一个作为中心点
public class MapminiOne : MonoBehaviour, IPointerClickHandler
{
    //创建地图脚本的引用,用来获取其中的装饰物集合
    public BoLingMaps boLingMaps;
    //玩家
    public Transform player;
    //地图的rectTransform
    private RectTransform _rectTransform;
    //玩家的对象
    public NavMeshAgent nav;
    //控制缩放的Slider
    public Slider Slider;

    private void Awake()
    {
        Slider.value = 1;
        _rectTransform = GetComponent<RectTransform>();

    }
    private void Start()
    {
        //生成地图装饰物
        for (int i = 0; i < boLingMaps.bodyList.Count; i++)
        {
            GameObject bodyimg = GameObject.Instantiate(Resources.Load<GameObject>("bodyimg"), transform);
            if (boLingMaps.bodyList[i].name.Contains("Tou"))
            {
                bodyimg.GetComponent<Image>().color = Color.red;
            }
            if (boLingMaps.bodyList[i].name.Contains("Tui"))
            {
                bodyimg.GetComponent<Image>().color = Color.yellow;
            }
            if (boLingMaps.bodyList[i].name.Contains("YiFu"))
            {
                bodyimg.GetComponent<Image>().color = Color.blue;
            }
            if (boLingMaps.bodyList[i].tag.Contains("Grass"))
            {
                bodyimg.GetComponent<Image>().color = new Color(0f, 0.4f, 0f, 1f); 
            }
            if (boLingMaps.bodyList[i].tag.Contains("Stone"))
            {
                bodyimg.GetComponent<Image>().color = Color.gray;
            }
            if (boLingMaps.bodyList[i].tag.Contains("Food"))
            {
                bodyimg.GetComponent<Image>().color = Color.red;
            }
            float x = boLingMaps.bodyList[i].transform.position.x / 100 * _rectTransform.sizeDelta.x - 200;//减去半径
            float y = boLingMaps.bodyList[i].transform.position.z / 100 * _rectTransform.sizeDelta.y - 200;
            bodyimg.transform.localPosition = new Vector2(x, y);
        }
    }
    private void Update()
    {
       
        //实时获取大地图的比例(100是柏林噪声地图的宽高)
        float x = nav.transform.position.x / 100;
        float y = nav.transform.position.z / 100;
        //中心点跟随移动
        _rectTransform.pivot = new Vector2(x, y);
        //滑动条控制缩放
        _rectTransform.localScale = Vector3.one * Slider.value;
        //滚轮控制缩放
        if (Input.GetAxis("Mouse ScrollWheel") != 0)
        {
            _rectTransform.localScale += Vector3.one * Input.GetAxis("Mouse ScrollWheel");
        }
    }

    public void OnPointerClick(PointerEventData eventData)
    {
        //mapImage 的标签
        if (eventData.pointerPressRaycast.gameObject.tag == "Map")
        {
            var isClick =
            RectTransformUtility.ScreenPointToLocalPointInRectangle(_rectTransform, eventData.position, null,
                out var point);
            float x = point.x / _rectTransform.sizeDelta.x * 100;
            float y = point.y / _rectTransform.sizeDelta.y * 100;
            var endpos = player.position + new Vector3(x, 0, y);
            nav.SetDestination(endpos);
        }
        //根据装饰物在场景的位置把位置映射在小地图上    BodyImage 是生成的装饰物image预制体的标签
        if (eventData.pointerPressRaycast.gameObject.tag == "BodyImage")
        {
            Debug.Log(eventData.pointerPressRaycast.gameObject.name);
            float x = eventData.pointerPressRaycast.gameObject.transform.localPosition.x / _rectTransform.sizeDelta.x * 100;
            float y = eventData.pointerPressRaycast.gameObject.transform.localPosition.y / _rectTransform.sizeDelta.y * 100;
            var endpos = player.position + new Vector3(x, 0, y);
            nav.SetDestination(endpos);
        }
        
    }
}

小地图二:

using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class MapminiTwo : MonoBehaviour, IPointerClickHandler
{
    //创建地图脚本的引用,用来获取其中的装饰物集合
    public BoLingMaps boLingMaps;
    //代表人物的图片
    public Image myImage;
    private RectTransform _rectTransform;
    //移动的主角
    public NavMeshAgent nav;

    void Awake()
    {
        _rectTransform = GetComponent<RectTransform>();
    }
    private void Start()
    {
        for (int i = 0; i < boLingMaps.bodyList.Count; i++)
        {
            GameObject bodyimg = GameObject.Instantiate(Resources.Load<GameObject>("bodyimg"), transform);
            if (boLingMaps.bodyList[i].name.Contains("Tou"))
            {
                bodyimg.GetComponent<Image>().color = Color.red;
            }
            if (boLingMaps.bodyList[i].name.Contains("Tui"))
            {
                bodyimg.GetComponent<Image>().color = Color.yellow;
            }
            if (boLingMaps.bodyList[i].name.Contains("YiFu"))
            {
                bodyimg.GetComponent<Image>().color = Color.blue;
            }
            if (boLingMaps.bodyList[i].tag.Contains("Grass"))
            {
                bodyimg.GetComponent<Image>().color = new Color(0f, 0.4f, 0f, 1f);
            }
            if (boLingMaps.bodyList[i].tag.Contains("Stone"))
            {
                bodyimg.GetComponent<Image>().color = Color.gray;
            }
            if (boLingMaps.bodyList[i].tag.Contains("Food"))
            {
                bodyimg.GetComponent<Image>().color = Color.red;
            }
            float x = boLingMaps.bodyList[i].transform.position.x / 100 * _rectTransform.sizeDelta.x;
            float y = boLingMaps.bodyList[i].transform.position.z / 100 * _rectTransform.sizeDelta.y;
            bodyimg.transform.localPosition = new Vector2(x, y);
        }
    }
    //点击ui人物移动
    public void OnPointerClick(PointerEventData eventData)
    {
        
        if (eventData.pointerPressRaycast.gameObject.tag == "Map")
        {
            //获取点击的坐标
            var isClicked =
                RectTransformUtility.ScreenPointToLocalPointInRectangle(_rectTransform, eventData.position, null,
                    out var point);
            //通过点击位置在小地图上的位置比例×实际的地图宽高,计算出3D坐标的位置
            float x = point.x / _rectTransform.sizeDelta.x * 100;
            float y = point.y / _rectTransform.sizeDelta.y * 100;

            var endpos = new Vector3(x, 0, y);
            //导航到对应位置
            nav.SetDestination(endpos);
        }
        if (eventData.pointerPressRaycast.gameObject.tag == "BodyImage")
        {
            Debug.Log(eventData.pointerPressRaycast.gameObject.name);
            float x = eventData.pointerPressRaycast.gameObject.transform.localPosition.x / _rectTransform.sizeDelta.x * 100;
            float y = eventData.pointerPressRaycast.gameObject.transform.localPosition.y / _rectTransform.sizeDelta.y * 100;
            var endpos = new Vector3(x, 0, y);
            nav.SetDestination(endpos);
        }
    }
    //人物移动映射到小地图
    void Update()
    {
        //实时获取游戏人物在大地图的比例,×地图宽高,给红点图片赋值
        float x = nav.transform.position.x / 100 * _rectTransform.sizeDelta.x;
        float y = nav.transform.position.z / 100 * _rectTransform.sizeDelta.y;
        myImage.transform.localPosition =  new Vector2(x, y);
    }
}

  • 13
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值