Unity | Tilemap系统

news2025/1/23 4:41:58

目录

一、准备工作

1.插件导入

2.资源导入

 二、相关组件介绍

1.Grid组件

2.Tilemap组件

3.Tile

4.Tile Palette

5.Brushes

三、动态创建地图

四、其他功能

1.移动网格上物体

2.拖拽缩放地图


        Unity Tilemap系统为2D游戏开发提供了一个直观且功能强大的平台,使得创建复杂且美观的游戏世界变得更加容易,Unity的Tilemap系统经过优化,能够高效地处理大量Tiles,确保游戏在各种设备上都能流畅运行。

一、准备工作

1.插件导入

2.资源导入

        提供一个我找了半天才找到的tile图像资源。因为我要做等距透视地图,所以需要是菱形,并且图片长=宽。

        当最终绘制的地图不合适时,可以调整图像的Pivot:

 二、相关组件介绍

1.Grid组件

        Grid组件是Unity中用于创建和管理网格(Grid)的基础组件,特别适用于2D游戏开发中的Tilemap系统。网格布局可以是矩形、六边形等。

  • Cell Size

        开发者可以定义每个网格单元的大小。这对于确保Tiles和其他元素在正确的位置上显示非常重要。

  • Cell Gap

        允许开发者在网格单元之间设置间隙,从而调整元素之间的距离。这样可以创建更复杂的布局效果。

  • CellLayout 

        枚举包括以下几种布局类型:

  1. Rectangle:矩形布局。单元格以矩形的形式排列,这是最常见的一种布局方式。
  2. Hexagon:六边形布局。单元格以六边形的形式排列,通常用于需要六边形网格的游戏或应用。
  3. Isometric:等距菱形布局。单元格以等距(菱形)的形式排列,常用于等距视角的游戏,例如模拟类游戏。
  4. IsometricZAsY:等距Z轴作为Y轴布局。这种布局类似于等距布局,但Z轴值将被添加为Y值。这种布局通常用于需要特殊等距视角效果的场景。
  • cellSwizzle

        用于重新排列网格单元格的坐标。具体来说, 允许将默认的 XYZ 单元格坐标重新排序为不同的排列方式。以下是一些可能的重排选项:

  1. XYZ:保持单元格位置不变。
  2. XZY:将单元格位置从 XYZ 重排为 XZY。
  3. YXZ:将单元格位置从 XYZ 重排为 YXZ。
  4. YZX:将单元格位置从 XYZ 重排为 YZX。
  5. ZXY:将单元格位置从 XYZ 重排为 ZXY。
  6. ZYX:将单元格位置从 XYZ 重排为 ZYX。

        Grid组件通常与Tilemap组件一起使用,以实现复杂的2D场景设计。Tilemap会自动对齐到Grid定义的网格上,使得绘制和管理Tiles变得更加容易。Grid组件提供了一些方便的方法,用于在世界坐标、局部坐标和网格坐标之间进行转换。这使得在网格上定位对象变得更加简单和直观。

        总结来说,Grid组件为Unity中的2D游戏开发提供了一个强大且灵活的基础结构,使得创建和管理基于网格的场景变得更加简单和高效。

2.Tilemap组件

        Unity的Tilemap系统是一个强大的工具,用于在2D游戏开发中创建和管理网格化的游戏世界。Tilemap组件是用于在场景中绘制瓦片(Tiles)的基础组件。它可以与Grid组件一起使用,以定义网格的大小和形状。

3.Tile

        Tilemap系统中的基本构建块。每个Tile代表一个小的图像或动画,可以重复使用来创建更大的图案或场景。Tiles可以包含碰撞信息、颜色等属性。

4.Tile Palette

        一个用户界面工具,允许开发者创建、编辑和管理Tiles。开发者可以将Tiles拖放到Tile Palette中,然后使用画笔工具将它们绘制到Tilemap上。

5.Brushes

        Brushes是用于在Tilemap上绘制Tiles的工具。Unity提供了多种预定义的Brushes,例如普通画笔、随机画笔等,开发者也可以创建自定义Brushes以满足特定需求。

  • Default Brush:默认的绘画刷,用于基本的Tile绘制操作。
  • GameObject Brush:用于在Tilemap上绘制GameObjects,而不仅仅是Tiles。
  • Group Brush:允许用户将多个Tiles组合在一起,并作为一个整体进行绘制。
  • Random Brush:可以随机选择预定义的Tiles进行绘制,适合创建更自然和多样化的Tilemap。
  • Line Brush:用于绘制直线形状的Tiles,方便创建路径或直线结构。

        总之,Unity Tilemap系统为2D游戏开发提供了一个直观且功能强大的平台,使得创建复杂且美观的游戏世界变得更加容易,Unity的Tilemap系统经过优化,能够高效地处理大量Tiles,确保游戏在各种设备上都能流畅运行。

三、动态创建地图

1.创建空物体Grid,添加Grid组件。

2.创建Grid的子物体Tilemap,添加Tilemap及Tilemap Renderer组件。

3.代码展示。

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

public class CreatTail : MonoBehaviour
{
    public Tilemap tilemap;
    public TileBase[] tiles; // 一个包含多个不同类型瓦片的数组
    int tileIndex = 0;

    private void Start()
    {
        GenerateMap();
    }

    void GenerateMap()
    {
        for (int x = 0; x < 20; x++)
        {
            for (int y = 0; y < 21; y++)
            {
                tileIndex = tileIndex == 0 ? 1 : 0;

                SetTile(new Vector3Int(x - 10, -y + 10, 0), tiles[tileIndex]);

            }
        }

#if UNITY_EDITOR
        string prefabPath = "Assets/Prefabs/Tilemap.prefab";
        //动态制作预制体
        UnityEditor.PrefabUtility.SaveAsPrefabAsset(tilemap.gameObject, prefabPath);

#endif
    }
    void SetTile(Vector3Int position, TileBase tile)
    {
        tilemap.SetTile(position, tile);
    }
}

4.效果展示

四、其他功能

1.移动网格上物体

        可移动的物体设置layer为第7层,并将下方代码拖到该物体身上。当移动物体时,如果目标格子有物体,则不能放置。

using UnityEngine;
using UnityEngine.Tilemaps;

public class DragManager : MonoBehaviour
{
    private bool isDragging = false;
    private Vector3 offset;
    private Camera mainCamera;
    private Vector3 lastPos;

    void Start()
    {
        mainCamera = Camera.main;

    }

    void OnMouseDown()
    {
        isDragging = true;
        offset = transform.position - GetMouseWorldPosition();
        lastPos=transform.position;

    }

    void OnMouseUp()
    {
        isDragging = false;

        // 获取鼠标位置对应的Tilemap位置
        Tilemap tilemap = FindObjectOfType<Tilemap>();
        Vector3Int cellPosition = tilemap.WorldToCell(GetMouseWorldPosition());

        // 将物体放置到格子中心
        //transform.position = tilemap.GetCellCenterWorld(cellPosition);
        //transform.position=new Vector3 (transform.position.x,transform.position.y,0);

        Vector3 targetPosition = tilemap.GetCellCenterWorld(cellPosition);
        targetPosition.z = 0;
        Collider2D[] hitCollider = Physics2D.OverlapPointAll((Vector2)targetPosition);
        if (hitCollider.Length<=0)
        {
            transform.position = targetPosition;
        }
        else
        {
            Debug.Log("Target position already occupied by another object.");
            foreach (var item in hitCollider)
            {
                Debug.Log(item.name);
            }
            if (hitCollider.Length==1&& hitCollider[0].name==transform.name)
            {
                transform.position = targetPosition;
            }
            else
            {
                transform.position = lastPos;
            }
        }
    }

    void Update()
    {
        if (isDragging)
        {
            Vector3 targetPosition = GetMouseWorldPosition() + offset;
            targetPosition.z = -1;
            transform.position = targetPosition;
        }
    }

    private Vector3 GetMouseWorldPosition()
    {
        Vector3 mouseScreenPosition = Input.mousePosition;
        mouseScreenPosition.z = -9;// mainCamera.nearClipPlane; // 确保z轴值正确
        return mainCamera.ScreenToWorldPoint(mouseScreenPosition);
    }
}

2.拖拽缩放地图

        拖拽地图时,如果焦点在物体身上,则不拖拽。

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

public class GameController : MonoBehaviour
{
    public float zoomSpeed = 0.1f;  // 缩放速度
    public float minZoom = 1f;    // 最小缩放值
    public float maxZoom = 3f;      // 最大缩放值

    private Vector2 dragOrigin;
    private Camera mainCamera;

    public bool drag;
    public float mapLength = 10f;   
    public float mapWidth = 10f;

    private void Start()
    {
        mainCamera = Camera.main;
        maxZoom = mainCamera.orthographicSize;
    }
    void Update()
    {
#if UNITY_EDITOR || UNITY_STANDALONE
        HandleMouseInput();
#elif UNITY_ANDROID || UNITY_IOS
        HandleTouchInput();
#endif
    }

#if UNITY_EDITOR || UNITY_STANDALONE
    private void HandleMouseInput()
    {
        // 放大/缩小
        if (Input.mouseScrollDelta.y != 0)
        {
            //Debug.Log(Input.mouseScrollDelta.y);
            Zoom(Input.mouseScrollDelta.y * zoomSpeed);
        }

        // 拖拽屏幕

        if (Input.GetMouseButtonDown(0))
        {
            Vector3 ray = Camera.main.ScreenToWorldPoint(Input.mousePosition);

            RaycastHit2D hit = Physics2D.Raycast(ray, Vector2.zero, 100, 1 << 7);

            // 检查是否有物体被射线击中
            if (hit.collider != null)
            {
                Debug.Log("Hit " + hit.collider.gameObject.name);
            }
            else
            {
                dragOrigin = Input.mousePosition;
                drag = true;
            }
            return;
        }
        //if (Input.GetMouseButtonDown(0))
        //{
        //    dragOrigin = Input.mousePosition;
        //    return;
        //}

        if (!Input.GetMouseButton(0)) { 
            drag = false;
            return; 
        }
        if (drag)
        {
            Vector3 difference = mainCamera.ScreenToViewportPoint((Vector2)Input.mousePosition - dragOrigin);
            Vector3 move = new Vector3(difference.x * mainCamera.orthographicSize, difference.y * mainCamera.orthographicSize, 0);

            mainCamera.transform.Translate(-move, Space.World);

            dragOrigin = Input.mousePosition;
        }
    }
#endif

#if UNITY_ANDROID || UNITY_IOS
    private void HandleTouchInput()
    {
        if (Input.touchCount == 2)
        {
            Touch touchZero = Input.GetTouch(0);
            Touch touchOne = Input.GetTouch(1);

            Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
            Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition;

            float prevMagnitude = (touchZeroPrevPos - touchOnePrevPos).magnitude;
            float currentMagnitude = (touchZero.position - touchOne.position).magnitude;

            float difference = currentMagnitude - prevMagnitude;

            Zoom(difference * zoomSpeed);
        }

        if (Input.touchCount == 1)
        {
            Touch touch = Input.GetTouch(0);

            if (touch.phase == TouchPhase.Began)
            {

                Vector3 ray = Camera.main.ScreenToWorldPoint(Input.mousePosition);

                RaycastHit2D hit = Physics2D.Raycast(ray, Vector2.zero, 100, 1 << 7);//只检测可拖拽的物体层
                if (hit.collider != null)
                {
                    Debug.Log("Hit " + hit.collider.gameObject.name);
                }
                else //没有点击到物体,则拖拽屏幕
                {
                    dragOrigin = touch.position;
                    drag = true;
                }
                return;
            }

            if (touch.phase != TouchPhase.Moved)
            {
                drag = false;
                return;
            }
            if (drag)
            {
                Vector3 difference = mainCamera.ScreenToViewportPoint(touch.position - dragOrigin);
                Vector3 move = new Vector3(difference.x * mainCamera.orthographicSize, difference.y * Camera.main.orthographicSize, 0);

                mainCamera.transform.Translate(-move, Space.World);

                dragOrigin = touch.position;
            }
        }
    }
#endif

    private void Zoom(float increment)
    {
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_ANDROID || UNITY_IOS
        Camera.main.orthographicSize = Mathf.Clamp(mainCamera.orthographicSize - increment, minZoom, maxZoom);
#endif
    }
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1814758.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

知网学术期刊《数学之友》投稿难度大吗?

知网学术期刊《数学之友》投稿难度的大小&#xff0c;实际上取决于多个因素的综合考量&#xff0c;包括论文的质量、研究方向的匹配度、期刊的审稿标准以及投稿者的学术背景等。 首先&#xff0c;从期刊的定位和特点来看&#xff0c;《数学之友》作为一份专注于数学领域的学术期…

利用R包“Phenotype”对表型值进行检查

首先&#xff0c;你需要确保你已经安装了R和RStudio&#xff08;如果你想用RStudio的话&#xff09;。然后&#xff0c;你可以按照以下步骤进行操作&#xff1a; 加载数据&#xff1a;首先&#xff0c;你需要加载你的表型数据。如果你的数据是以CSV、Excel等格式保存的&#x…

vue2中如何动态渲染组件

vue2中如何动态渲染组件 动态渲染组件代码解读通过函数调用渲染组件 封装一个函数调用的二次确认弹窗如何让外部知道用户点击了取消还是确定呢&#xff1f; 思考小结 vue2 的项目中&#xff0c;main.js 文件中有一个挂载 App.vue 组件的方法&#xff1a; new Vue({name: Root,…

Python酷库之旅-比翼双飞情侣库(01)

目录 一、xlrd库的由来 二、xlrd库优缺点 1、优点 1-1、支持多种Excel文件格式 1-2、高效性 1-3、开源性 1-4、简单易用 1-5、良好的兼容性 2、缺点 2-1、对.xlsx格式支持有限 2-2、功能相对单一 2-3、更新和维护频率低 2-4、依赖外部资源 三、xlrd库的版本说明 …

Linux C语言:多级指针(void指针和const)

一、多级指针 把一个指向指针变量的指针变量&#xff0c;称为多级指针变量对于指向处理数据的指针变量称为一级指针变量指向一级指针变量的指针变量称为二级指针变量 1、二级指针变量的说明形式 <数据类型> ** <指针名> &#xff1b; 一张图理解二级指针 2、多…

intouch的报警怎么发到短信/微信上

Intouch 与 GRM_OPCGATE 通讯协议 一、安装 FS GateWay&#xff08;INTOUCH 驱动盘里有这个驱动程序&#xff0c;根目录:\INTOUCH10.0\DA Server\WW\FSG-1.5.100&#xff09; 。注&#xff1a;安装 INTOUCH 时&#xff0c;可能已同时安装了这个驱动&#xff0c;如图在下查看&am…

【Java】如何提升RocketMQ顺序消费性能?

一、问题解析 我们先来了解一下 RocketMQ 顺序消费的实现原理。RocketMQ 支持局部顺序消息消费&#xff0c;可以保证同一个消费队列上的消息顺序消费。例如&#xff0c;消息发送者向主题为 ORDER_TOPIC 的 4 个队列共发送 12 条消息&#xff0c; RocketMQ 可以保证 1、4、8 这…

ultralytics框架讲解

ultralytics简介 Ultralytics是一个开源的计算机视觉和深度学习框架&#xff0c;旨在简化训练、评估和部署视觉模型的过程。该框架提供了一系列流行的视觉模型&#xff0c;包括YOLOv5、YOLOv4、YOLOv3、YOLOv3-tiny、YOLOv5-tiny、EfficientDet、PAN、PP-YOLO等&#xff0c;并提…

西门子PLC数据 转IEC61850项目案例

1 案例说明 设置网关采集西门子PLC数据把采集的数据转成IEC61850协议转发给其他系统。 2 VFBOX网关工作原理 VFBOX网关是协议转换网关&#xff0c;是把一种协议转换成另外一种协议。网关可以采集西门子&#xff0c;欧姆龙&#xff0c;三菱&#xff0c;AB PLC&#xff0c;DLT6…

【Ardiuno】实验ESP32单片机完成搭建简易Web服务器功能(图文)

今天&#xff0c;小飞鱼继续来测试使用ESP32来实现简易的wifi无线web服务器功能。使用Ardiuno平台编辑器输入以下示例代码&#xff1a; #include <WiFi.h> #include <WiFiClient.h> #include <WebServer.h> #include <ESPmDNS.h>const char* ssid &q…

QT安装及项目创建

一、QT安装 1、安装qt_creater 方法一&#xff1a; 镜像文件&#xff1a;在2024-6-12&#xff1a;版本已经更新到了6.7 下载地址&#xff1a;https://download.qt.io/archive/qt/ 方法二&#xff1a; 百度网盘&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1D0EmH…

ssm大学校园慈善拍卖网站-计算机毕业设计源码80891

摘要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对大学校园慈善拍卖网站等问题&#xff0c;对大…

软考-架构设计师-综合知识总结(试卷:2009~2022)(下篇)

说明 本文档对2009到2022年试卷的综合知识进行了归纳总结&#xff0c;同时对叶宏主编的《系统架构设计师教程》划分重点。 第十七章&#xff1a;通信系统架构设计 17.2 考题总结 第十八章&#xff1a;安全架构设计 18.1 重要知识点 18.2 考题总结 第十九章&#xff1a;大数据…

半导体晶圆切割之高转速电主轴解决方案

随着科技的飞速进步&#xff0c;集成电路技术已经成为了现代电子设备中不可或缺的核心组件。而在集成电路的生产过程中&#xff0c;半导体晶圆切割技术更是扮演着举足轻重的角色。这不仅关系到半导体芯片的制造成本和效率&#xff0c;更是决定了整个集成电路产业的发展速度和方…

T113跟官方教程安装docker出错

官方示例步骤&#xff1a; 会遇到网络问题&#xff0c;如图&#xff1a; 尝试直接去网上下载gpg&#xff0c;但是遇到教程后面一步也要访问该网站&#xff1a; 跳过该步骤&#xff0c;后续安装docker还会报错&#xff1a; 解决方法&#xff1a;换源&#xff0c;不必跟官方教程了…

给文件夹加密的最简单方法

安当TDE透明加密针对文件夹数据加密的保护方案主要包括以下几个方面&#xff1a; 1. 透明加密机制&#xff1a; 用户无需关心数据的加密和解密过程&#xff0c;操作文件夹时就像处理普通数据一样。加密和解密操作在后台自动进行&#xff0c;对用户和应用程序透明。 2. 高性能加…

现在转行转岗AI产品经理真的是一个好时机吗?

前言 2024年过去一半时间了。 很多朋友年初就计划转岗产品经理&#xff0c;但又苦于没有经验、知识不牢固…… 经常能看到有朋友问&#xff1a;转岗产品经理会有哪些坑要注意&#xff1f;有什么建议&#xff1f; 综合大家问得比较多的问题&#xff0c;我们发现&#xff1a;很…

GStreamer应用程序——Pads 和 capabilities(功能)

Pads 和 capabilities(功能) 正如我们在元素中看到的&#xff0c;pads是元素与外部世界的接口。来自一个的数据流元素的源pad到另一个元素的接收pad。特定类型的元素可以处理的媒体将被pad暴露能力。我们将在本章后面更多地讨论功能 &#xff08;参见pad的功能&#xff09;。 …

k8s之包管理器Helm

每个成功的软件平台都有一个优秀的打包系统&#xff0c;比如Debian、Ubuntu 的 apt&#xff0c;RedHat、CentOS 的 yum。Helm 则是 Kubernetes上 的包管理器&#xff0c;方便我们更好的管理应用。 一、Helm 的相关知识 1.1 Helm的简介 在没使用 helm 之前&#xff0c;向 kuber…

中国四大高原矢量示意图分享

我们在《中国地势三级阶梯示意图分享》一文中&#xff0c;为你分享了中国三级阶梯示意图的矢量文件。 现在&#xff0c;我们再为你分享中国四大高原的矢量示意图文件&#xff0c;你可以在文末查看文件的领取方法。 我国四大高原是如何划分的&#xff1f; 中国四大高原分别为…