1. 项目概述:为什么Tilemap缩放是个“坑”?
如果你在Unity里用过Tilemap做过2D游戏,尤其是那种需要适配多种分辨率或者有复杂层级关系的项目,那你大概率踩过Tilemap缩放的坑。我最近就在一个横版卷轴项目里,为了一个“简单”的需求——让背景层Tilemap随着摄像机平滑缩放以营造景深效果——折腾了整整两天。不是Tilemap直接糊成一团,就是碰撞体对不上,再不然就是Tile的精灵图变得锯齿丛生。这让我意识到,Unity Tilemap的缩放,远不是选中GameObject然后拉一下Scale那么简单。
Unity的Tilemap系统非常强大,它本质上是一个基于网格的高效2D场景构建工具。但正因为其结构特殊(由Grid、Tilemap、Tilemap Renderer、Tilemap Collider等多个组件协同工作),当你试图改变其显示大小时,会涉及到渲染、物理、编辑效率等多个层面。网上很多教程只讲其一,不讲其二,更少有人把三种主流缩放方式(编辑器操作、组件参数调整、运行时代码控制)放在一起对比,讲清楚各自的原理、适用场景和致命陷阱。
所以,这篇内容就是把我踩过的坑、试过的错、以及最终梳理出来的解决方案,系统地分享给你。无论你是想微调Tilemap在场景中的布局,还是实现动态的缩放效果,或是解决多分辨率适配问题,理解这三种方式的区别,都能帮你省下大量调试时间。我们会深入编辑器缩放、通过组件参数(如Tilemap Renderer)缩放、以及通过代码(如Transform或Material)缩放这三种方法,不仅告诉你怎么做,更重点剖析“为什么”要这么做,以及每种方法背后可能引发的连锁反应。
2. 核心概念与三种缩放方式总览
在深入细节之前,我们必须统一几个关键概念,否则讨论缩放就是在鸡同鸭讲。
首先,要分清“逻辑网格”与“视觉呈现”。Tilemap的核心是Grid组件,它定义了一个不可见的、无限延伸的坐标网格。每个格子(Cell)是这个网格的基本单位。Tilemap组件挂载在拥有Grid组件的物体下,它负责将Tile(瓦片资源)填充到这些格子里。Tilemap Renderer组件则负责把这些逻辑上的“填充信息”绘制到屏幕上。当我们说“缩放Tilemap”时,可能指:
- 缩放整个GameObject(包含Grid),改变网格世界空间的大小。
- 缩放Tilemap的渲染输出,但不改变网格逻辑。
- 缩放每个Tile所使用的精灵图(Sprite)的像素密度。
其次,理解缩放影响的维度:
- 碰撞体(Tilemap Collider 2D):缩放是否影响碰撞体的形状和位置?这直接关系到游戏玩法。
- 渲染质量:缩放是否会引入像素锯齿或模糊?这影响视觉表现。
- 编辑体验:在Unity编辑器中,缩放后的Tilemap是否还能方便地用笔刷编辑?
- 性能:某些缩放方式是否会增加额外的渲染开销?
基于以上,我们可以将Unity中调整Tilemap视觉尺寸的方法归纳为三类:
2.1 方式一:编辑器直接缩放(Transform.Scale)
这是最直觉、最“暴力”的方法。在Hierarchy中选中包含Grid和Tilemap的父级GameObject,然后在Inspector中修改Transform组件的Scale值(如X: 2, Y: 2)。
它做了什么?直接改变了该GameObject及其所有子级在世界空间中的变换矩阵。这意味着Grid定义的每个逻辑单元格的物理尺寸变大了,所有基于此Grid的Tilemap、其上的碰撞体、以及子物体都会同步放大。
优点:
- 操作极其简单,符合常规3D/2D对象操作习惯。
- 影响全面,一次修改,视觉、碰撞、逻辑位置全部同步缩放。
潜在的“坑”:
- 编辑灾难:如果你在缩放后的Grid上继续用Tilemap笔刷编辑,会发现笔刷的“格子”对准变得极其困难,因为你的视觉判断(看放大后的瓦片)和逻辑格子(原始大小)可能对不上。这很容易导致瓦片错位。
- 碰撞体缩放:
Tilemap Collider 2D默认会跟随Transform的Scale。如果你的Tile碰撞体是Composite Collider 2D(由多个碰撞体组合而成),缩放可能导致碰撞体形状复杂化或产生意想不到的缝隙。 - 子物体错位:如果该GameObject下还有其他用于标记点(如出生点、事件触发点)的空物体,它们的相对位置也会被缩放,可能需要你手动重新计算位置。
注意:这种方式动的是“世界根基”(Grid),通常不推荐作为调整Tilemap视觉大小的首选方法,尤其对于需要频繁编辑的区块。
2.2 方式二:通过渲染组件参数缩放(Tilemap Renderer)
这是一种更“温和”且针对渲染结果的方法。它不改变Grid和Tilemap的逻辑结构,只改变最终绘制到屏幕上的图像大小。
如何操作?选中TilemapGameObject,在Inspector中找到Tilemap Renderer组件。这里并没有一个直接的“Scale”参数。缩放主要通过以下两种途径实现:
- 修改
Grid组件的Cell Size:这是更根本的方法。Grid组件的Cell Size定义了每个逻辑格子对应世界空间中的大小。将Cell Size从(1,1,0)改为(2,2,0),那么每个Tile就会占据2x2的世界单位,视觉上就放大了。注意:这会影响所有基于此Grid的Tilemap。 - 使用材质属性(Material Property):为
Tilemap Renderer指定一个自定义材质(而不是默认的Sprites-Default),然后通过代码或材质属性块(MaterialPropertyBlock)来修改材质的_MainTex_ST(缩放和平移)等属性,实现对渲染图像的缩放。这种方式更灵活,但需要一些Shader基础。
优点:
- 保持逻辑完整:Grid的坐标系不变,笔刷编辑体验不受影响。所有基于格子坐标的逻辑计算(如A*寻路)依然有效。
- 针对性影响:通过
Grid的Cell Size缩放,可以精准控制所有关联Tilemap的视觉比例;通过材质缩放,可以只影响单个Tilemap的渲染。
潜在的“坑”:
Cell Size缩放的影响:虽然不破坏编辑逻辑,但改变了世界单位与格子单位的对应关系。如果你游戏中的其他系统(如物理运动速度、触发器范围)是以世界单位(units)设计的,而Tilemap是以格子(cells)设计的,缩放Cell Size后需要重新协调两者关系。- 材质缩放的质量问题:对精灵纹理进行缩放,如果缩放比例不是整数倍(如1.5倍),很容易导致纹理过滤产生模糊或锯齿。需要根据精灵的
Filter Mode(Point, Bilinear等)仔细调整。 - 额外性能开销:使用MaterialPropertyBlock进行每帧动态缩放,虽然比更换材质实例更高效,但仍比静态渲染多一些开销。
2.3 方式三:通过运行时代码控制缩放
这主要用于实现动态效果,如镜头拉近拉远时背景层的视差缩放、关卡切换时的平滑缩放动画等。
常用手段:
- 控制Transform.Scale:在
Update或协程中,通过代码动态修改Transform.localScale。这是方式一的程序化版本,因此也继承其所有优缺点(影响碰撞、编辑逻辑等)。通常用于不需要再编辑的、作为整体动态变化的Tilemap。 - 控制Grid.CellSize:动态修改
Grid.cellSize。这能实现所有子Tilemap的同步动态缩放,且保持逻辑坐标。但注意,频繁修改可能触发物理引擎重新计算碰撞体(如果碰撞体依赖Grid),有性能损耗。 - 控制材质属性:通过
MaterialPropertyBlock动态设置材质的缩放参数。这是实现单个Tilemap高质量动态缩放最推荐的方式,因为它只影响渲染,不扰动物理和逻辑。
优点:
- 动态灵活:可以实现帧间平滑动画和交互响应。
- 方案可选:可以根据需要选择影响逻辑(用Scale/Grid)或只影响渲染(用材质)。
潜在的“坑”:
- 性能与频度:每帧修改Scale或CellSize,尤其是当Tilemap复杂时,可能引起不必要的重计算。MaterialPropertyBlock是相对高效的选择。
- 插值动画的副作用:对Scale或CellSize进行Lerp插值,如果缩放比例是非均匀的(如X和Y缩放速度不同),在动画中间状态可能导致视觉扭曲。确保插值曲线平滑且比例一致。
- 与物理的同步:如果缩放影响了碰撞体(Scale或Grid方式),需要确保物理引擎能正确响应。有时可能需要手动禁用再启用碰撞体组件,或调用
CompositeCollider2D.GenerateGeometry()来强制更新复合碰撞体几何形状。
3. 三种方式深度对比与实战选择
光知道是什么还不够,我们必须把它们拉到同一个战场上,从多个维度进行实战化对比,才能知道什么情况下该用哪一招。下面这个表格是我根据实际项目经验总结的对比清单:
| 对比维度 | 编辑器直接缩放 (Transform.Scale) | 组件参数缩放 (Grid.CellSize / 材质) | 运行时代码控制 |
|---|---|---|---|
| 核心原理 | 修改物体世界变换矩阵,影响所有子节点。 | Grid.CellSize: 改变网格单位尺寸。 材质: 修改UV变换,影响采样。 | 程序化驱动上述两种方式之一。 |
| 影响范围 | 全局:视觉、碰撞、子物体位置、编辑网格。 | Grid.CellSize: 所有关联Tilemap的视觉与逻辑单位。 材质: 仅该渲染器的视觉输出。 | 取决于采用哪种底层方式。 |
| 编辑体验 | 极差。缩放后笔刷难以对准逻辑网格,极易误操作。 | Grid.CellSize:好。逻辑网格与视觉同步缩放,笔刷依然精准。 材质:好。不影响编辑。 | 不涉及编辑时操作。 |
| 碰撞体影响 | 直接影响。Tilemap Collider 2D会随之缩放,可能导致复杂碰撞体异常。 | Grid.CellSize:直接影响。碰撞体随网格单位变化。 材质:无影响。纯视觉。 | 同其所采用的基础方式。 |
| 渲染质量 | 依赖精灵纹理本身的过滤设置。非整数倍缩放易模糊。 | Grid.CellSize: 同左,但更易控制为整数倍。 材质: 可精细控制,可通过Shader实现高质量缩放。 | 同其所采用的基础方式。 |
| 性能开销 | 低(静态时)。 | Grid.CellSize: 低(静态时)。修改可能触发物理更新。 材质: 低至中,使用MaterialPropertyBlock动态修改开销较小。 | Scale/Grid: 中,每帧修改可能带来重计算。 材质: 低,推荐方式。 |
| 典型应用场景 | 1. 一次性确定不再修改的静态背景。 2. 作为整体预制件(Prefab)的一部分进行缩放。 | Grid.CellSize: 1. 统一调整整个“图层”或“关卡块”的尺寸。 2. 适配不同逻辑单位的需求。 材质: 1. 实现单个Tilemap的视觉特效(如热扭曲、水波)。 2. 高质量的非整数倍静态缩放。 | 1. 动态景深(背景层随镜头缩放)。 2. 关卡过渡动画。 3. 交互式放大镜效果。 |
如何选择?我的实战决策流程:
首先问:是否需要动态变化?
- 是-> 进入“运行时代码控制”范畴。接着问:动态缩放需要影响碰撞吗?
- 需要 -> 考虑使用
Grid.cellSize(如果影响多个Tilemap)或Transform.localScale(如果作为整体)。务必测试物理稳定性。 - 不需要 ->优先使用MaterialPropertyBlock控制材质缩放,这是性能与效果的最佳平衡点。
- 需要 -> 考虑使用
- 否-> 进入静态调整。
- 是-> 进入“运行时代码控制”范畴。接着问:动态缩放需要影响碰撞吗?
对于静态调整,问:缩放后还需要频繁编辑这个Tilemap吗?
- 需要 ->绝对不要用Transform.Scale。选择调整
Grid组件的Cell Size。这是保证后续编辑顺畅的生命线。 - 不需要 -> 可以权衡。如果该Tilemap是一个独立模块(如一个装饰物集合),用Transform.Scale打包成Prefab更方便。如果它和其他Tilemap共享Grid,则仍应用
Cell Size以保证视觉统一。
- 需要 ->绝对不要用Transform.Scale。选择调整
最后,永远检查渲染质量:
- 无论用哪种方式,如果缩放比例不是整数倍(1,2,3...),请务必检查精灵的
Filter Mode。对于像素风游戏,通常设置为Point (no filter)以防止模糊,但这在非整数倍缩放时会产生锯齿。你可能需要根据目标缩放比例,预先准备不同分辨率的精灵图集,或者使用专门的像素缩放Shader。
- 无论用哪种方式,如果缩放比例不是整数倍(1,2,3...),请务必检查精灵的
4. 分步实操:从理论到实现
知道怎么选,接下来我们动手实现最常见的两种需求:静态调整整体大小和实现动态景深缩放。
4.1 场景一:静态调整——让整个关卡区块变大1.5倍
假设你有一个已经搭建好的平台跳跃关卡区块,所有Tilemap都基于同一个Grid。现在你想把这个区块整体放大1.5倍,以便在更大的屏幕空间上使用。
错误做法(新手常见):
- 在Hierarchy中选中最顶层的
GridGameObject。 - 在Inspector中将
Transform的Scale从(1,1,1)改为(1.5, 1.5, 1)。 - 保存场景,发现笔刷对不齐,碰撞体感觉“不对”,后悔莫及。
正确做法(通过Grid.CellSize):
- 备份场景:在进行任何全局性修改前,这是铁律。
- 定位核心Grid:在Hierarchy中找到定义整个关卡区块逻辑网格的那个
GridGameObject。 - 计算新Cell Size:假设原来的
Grid组件Cell Size是X=1, Y=1(默认值)。放大1.5倍,新的Cell Size应为X=1.5, Y=1.5。 - 修改参数:在Inspector中,将
Grid组件的Cell Size字段修改为(1.5, 1.5, 0)。 - 立即观察:你会发现场景视图(Scene)中,所有关联的Tilemap视觉上瞬间放大了1.5倍,但它们的逻辑格子坐标(在Tilemap组件里看到的)完全没有变。
- 检查碰撞体:选中带有
Tilemap Collider 2D的Tilemap,在Scene视图中勾选Collider可视化。确认碰撞体的形状和大小是否同步正确缩放。对于Composite Collider 2D,如果发现碰撞形状没有更新,可以尝试在Inspector中点击Geometry Type旁边的齿轮图标,选择Regenerate Geometry(重新生成几何体)来强制刷新。 - 验证编辑功能:尝试使用Tilemap笔刷工具,在缩放后的区域绘画。你会发现笔刷仍然完美地贴合每一个放大后的格子,编辑体验无损。
实操心得:修改
Cell Size后,原来以世界单位(units)放置的游戏物体(如玩家、敌人、金币)可能看起来位置不对了,因为它们相对于放大后的Tilemap位置变了。你需要调整的是这些物体的世界坐标,或者更好的做法是:从一开始就使用Grid的CellToWorld和WorldToCell方法来进行坐标转换,这样无论Cell Size如何变化,你的游戏逻辑都能基于格子坐标运行,从而自动适配。
4.2 场景二:动态实现——背景层随摄像机缩放产生景深
我们需要一个背景层Tilemap,当摄像机拉近时,它缩放得慢一些(显得更远);当摄像机拉远时,它缩放得快一些。这通常通过修改材质属性来实现。
步骤详解:
准备工作:
- 创建一个用于背景的Tilemap,确保它与主地形Tilemap使用不同的
Grid父物体。这是为了能独立控制其缩放而不影响主场景。 - 为这个背景Tilemap的
Tilemap Renderer创建一个新的材质实例。不要直接使用默认材质,以免影响其他对象。你可以复制Sprites-Default材质,重命名为“BackgroundScalingMat”。 - 将新材质赋给背景Tilemap Renderer。
- 创建一个用于背景的Tilemap,确保它与主地形Tilemap使用不同的
编写控制脚本: 创建一个C#脚本,命名为
BackgroundParallaxScaler.cs,挂载到背景Tilemap或其父物体上。using UnityEngine; public class BackgroundParallaxScaler : MonoBehaviour { public Camera targetCamera; // 主摄像机 public float baseOrthographicSize = 5f; // 摄像机的基准正交大小 public float scaleMultiplier = 0.5f; // 缩放系数,小于1表示比摄像机缩放慢 private MaterialPropertyBlock m_PropertyBlock; private TilemapRenderer m_Renderer; private float m_InitialScale; void Start() { m_Renderer = GetComponent<TilemapRenderer>(); if (m_Renderer == null) { Debug.LogError("BackgroundParallaxScaler requires a TilemapRenderer component."); return; } m_PropertyBlock = new MaterialPropertyBlock(); // 获取材质初始的缩放值(假设材质使用_MainTex_ST,其中xy是缩放) m_Renderer.GetPropertyBlock(m_PropertyBlock); Vector4 initialST = m_PropertyBlock.GetVector("_MainTex_ST"); m_InitialScale = initialST.x; // 通常x和y缩放相同,取x即可 if (targetCamera == null) targetCamera = Camera.main; } void Update() { if (m_Renderer == null || targetCamera == null) return; // 计算基于摄像机缩放的背景缩放比例 float cameraScaleRatio = targetCamera.orthographicSize / baseOrthographicSize; // 背景缩放比例 = 初始缩放 * (1 + (摄像机比例变化 - 1) * 系数) // 当cameraScaleRatio=1时,背景缩放为初始值。 // 当系数为0.5时,背景缩放速度是摄像机的一半。 float targetScale = m_InitialScale * (1 + (cameraScaleRatio - 1) * scaleMultiplier); // 通过MaterialPropertyBlock设置新的缩放值,避免创建新的材质实例 m_Renderer.GetPropertyBlock(m_PropertyBlock); m_PropertyBlock.SetVector("_MainTex_ST", new Vector4(targetScale, targetScale, 0, 0)); m_Renderer.SetPropertyBlock(m_PropertyBlock); } }参数配置与解释:
baseOrthographicSize:这是你设计关卡时摄像机默认的“标准”大小。所有缩放计算将以此为基础。scaleMultiplier:这是景深系数。- 设为
0:背景完全不缩放,固定大小。 - 设为
0.5:背景缩放速度是摄像机的一半。例如,摄像机放大2倍,背景只放大1.5倍。 - 设为
1:背景与摄像机同步缩放,失去景深效果。 - 设为
-0.5:会产生反向视差(摄像机放大,背景缩小),用于特殊效果。
- 设为
运行与微调:
- 运行游戏,在运行时动态修改摄像机的
orthographicSize(例如通过一个测试UI滑块),观察背景Tilemap的平滑缩放效果。 - 调整
scaleMultiplier直到获得满意的景深感。
- 运行游戏,在运行时动态修改摄像机的
注意事项:这种方法只缩放纹理,不改变碰撞体(背景通常不需要碰撞)和逻辑网格位置。性能开销极小,因为
MaterialPropertyBlock只传递数据给GPU,不破坏渲染合批。确保你的材质Shader支持_MainTex_ST这个属性(绝大多数Sprite Shader都支持)。
5. 常见“坑点”排查与性能优化指南
即使按照最佳实践操作,在实际项目中你还是可能遇到一些棘手的问题。下面是我遇到过的典型问题及其解决方案。
5.1 问题一:缩放后Tilemap渲染出现缝隙或重叠
现象:在缩放Tilemap(尤其是非整数倍缩放)后,瓦片之间出现了细小的透明缝隙,或者相反,瓦片边缘重叠了。
原因分析:
- 纹理边缘(Border)问题:这是最常见的原因。精灵纹理在导入时,如果
Mesh Type为Full Rect,并且纹理周围没有留出足够的透明像素边缘,在进行缩放或旋转时,GPU纹理采样可能会轻微越界到相邻的瓦片上,导致缝隙或颜色污染。 - 浮点数精度误差:当缩放比例是非整数,或者通过复杂计算得到时,瓦片的位置计算可能产生微小的浮点数误差,累积起来导致渲染位置偏差。
解决方案:
- 检查纹理导入设置:在Project窗口选中你的精灵图集或单个精灵,在Inspector中:
- 确保
Mesh Type为Tight(对于像素艺术)或为Full Rect时,适当增加Extrude Edges的值(如1-2个像素)。 - 检查
Wrap Mode是否为Clamp,防止采样到纹理之外。 - 对于图集,确保
Sprite Editor中的每个精灵边界框(bounding box)准确无误,没有相互侵入。
- 确保
- 使用像素对齐:对于像素风游戏,可以考虑使用
Pixel Perfect Camera组件,并确保Grid和Tilemap的位置是整数(或半整数,取决于PPU)。缩放时也尽量保持整数倍关系。 - 微调Shader:如果问题依然存在,可以创建一个自定义的Sprite Shader,在片段着色器中,对UV坐标进行一个极微量的收缩(例如,减去一个非常小的epsilon值),这可以强制采样点远离边缘。但这属于进阶操作。
5.2 问题二:缩放导致Tilemap Collider 2D性能下降或表现异常
现象:缩放后,角色移动时卡顿,或者碰撞检测时有时无。
原因分析:
- 碰撞体几何复杂度激增:当对包含
Composite Collider 2D的Tilemap进行非均匀缩放(如X和Y缩放值不同)或频繁动态缩放时,Unity需要重新计算并简化碰撞体多边形。复杂的Tilemap可能会产生顶点数极高的碰撞体,严重消耗CPU。 - 静态碰撞体被标记为动态:运行时通过代码修改
Transform.scale或Grid.cellSize,会导致物理引擎将该碰撞体从“静态”重新归类为“动态”或“运动学”,这会改变其优化处理方式,可能增加开销。
解决方案与优化建议:
- 避免运行时缩放碰撞体:如果可能,动态缩放只应用于视觉(用材质),保持碰撞体所在GameObject的Scale和Grid不变。这是最根本的优化。
- 简化碰撞几何:在
Tilemap Collider 2D组件中:- 使用
Maximum Tile Slope来忽略缓坡。 - 如果不需要精确到每个像素的碰撞,可以创建一个更简化的
Sprite作为Tile的Collider Sprite,而不是使用默认的精灵轮廓。
- 使用
- 分离碰撞层:如果Tilemap中只有部分格子需要碰撞,考虑使用两个Tilemap:一个纯视觉(无碰撞器),另一个只包含碰撞格子(简化图形+碰撞器)。然后只缩放视觉层。
- 预计算与缓存:如果动态缩放碰撞体不可避免,不要每帧都修改。而是在缩放变化完成后,手动调用一次
CompositeCollider2D.GenerateGeometry(),并考虑将物理更新频率(Physics 2D设置中的Simulation Update Mode)调低。
5.3 问题三:在缩放后的Tilemap上编辑困难
现象:使用Transform.Scale放大Tilemap后,Tilemap笔刷工具无法准确地在格子上绘画,总是画歪。
原因与根治方法: 这个问题没有完美的补救措施,因为编辑器的笔刷工具是基于未缩放的Grid逻辑坐标工作的。当你放大了Transform,视觉反馈和逻辑坐标产生了偏差。
- 唯一可靠的解决方案是回退:撤销(Ctrl+Z)对Transform的Scale修改。然后采用修改
Grid.Cell Size的方式来达到视觉缩放的目的。 - 如果无法回退:你可以尝试先将这个Tilemap的所有内容通过
Tilemap Editor菜单中的Save As Asset功能保存为一个Tilemap Asset。然后重置其父级GameObject的Scale为(1,1,1),再通过修改Grid.Cell Size放大,最后用笔刷工具配合保存的Asset进行局部修复。这个过程非常繁琐,凸显了从一开始就选对方法的重要性。
5.4 性能优化要点总结
- 静态优于动态:尽可能在编辑期确定缩放,而非运行时。
- 材质缩放优于变换缩放:对于动态视觉缩放,优先使用
MaterialPropertyBlock修改材质属性,其性能影响远小于修改Transform或Grid。 - 合批考量:修改
Transform.scale或Grid.cellSize通常不会打断Sprite Renderer的静态合批(如果满足其他条件)。但动态修改可能会。而使用MaterialPropertyBlock设置每实例数据,是支持GPU实例化的,性能很好。 - 物理更新最小化:物理系统对缩放敏感。将需要动态缩放的对象设置为
Rigidbody2D的Body Type为Kinematic,可以给予更多控制权,并避免物理引擎的自动连续重计算。 - 精度与性能平衡:非整数倍缩放和极高的缩放比例会要求更高的渲染精度,可能触发更昂贵的纹理采样。在移动平台,要严格测试缩放带来的性能影响。
最后,我的个人体会是,处理Tilemap缩放,本质是在逻辑一致性、编辑便利性、渲染质量和运行时性能之间寻找平衡点。没有一种方法放之四海而皆准。在项目初期就规划好Tilemap的层级结构(哪些层共享Grid,哪些层独立),明确哪些需要动态效果,能为后续开发避免无数麻烦。记住那个黄金法则:需要编辑的,动Cell Size;需要动态视觉的,动Material;除非万不得已,别动Transform.Scale。把这套思路理清,Tilemap缩放这个“坑”,你就能稳稳当当地跨过去了。