关于 unity-2d
unity-2d 是 Unity 2D 项目开发参考技能,面向 Unity 开发者。内容涵盖精灵、Tilemap、2D 物理、URP 照明、渲染顺序及相关脚本 API。
主要功能
- 012D 项目设置与所需程序包
- 02精灵编辑、渲染和图集
- 03Tilemap 创建与脚本操作
- 042D 物理组件和查询
- 05URP 2D 灯光与排序
适用场景
- 01设置 Unity 2D 项目
- 02创建并渲染精灵场景
- 03实现 2D 碰撞和移动
- 04配置 URP 2D 照明
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ nice-wolf-studio/ unity-claude-skills --skill unity-2d安装后在 Claude Code 中输入/unity-2d确认已加载。
附带文件references/sprites-and-atlas.mdreferences/tilemaps.md
详细介绍
Unity 2D 开发
2D 项目设置
Unity 支持创建专用的 2D 项目。启动 2D 项目时:
- 创建新项目时,选择 2D 模板(或选择 2D (URP) 以支持 2D 光照)
- 2D 模板会自动安装所需的软件包:2D Sprite、2D Tilemap Editor、2D Animation
- 场景视图默认采用正交视图(自上而下的 XY 平面)
- 相机默认设置为正交投影
- 导入的图像默认使用 Sprite(2D and UI)纹理类型
文档中的核心 2D 子系统:
- Sprites:“2D 图形对象”——2D 游戏的基础
- Tilemaps:“一种 GameObject,可让你使用图块和网格叠加快速创建 2D 关卡”
- 2D Physics:专用物理系统,包含针对 2D 优化的组件
- 2D Rendering in URP:2D 光源、光照效果和像素化视觉风格
来源:https://docs.unity3d.com/6000.3/Documentation/Manual/Unity2D.html
Sprites 和 SpriteRenderer
Sprite 资源
Sprites 是“可在 Unity 项目中使用的一种 2D 资源”。它们是 2D 图形对象,并具备专门的导入和管理功能。必须安装 2D Sprite 软件包(2D 模板已包含此软件包)。
Sprite 的主要功能:
- 从纹理导入 Sprites 或 spritesheet
- 使用 Sprite Editor 从纹理中切割 Sprites(切片)
- 应用裁剪以移除透明区域
- 为 Sprite 物理创建碰撞几何体
- 使用 9-slicing,以不同尺寸重复利用 Sprites
- 使用 Masking 隐藏或显示 Sprite 或 Sprite 组的部分区域
来源:https://docs.unity3d.com/6000.3/Documentation/Manual/sprite/sprite-landing.html
SpriteRenderer 组件
SpriteRenderer 组件控制 Sprites 在场景中的显示方式。主要属性:
| 属性 | 说明 |
|---|---|
sprite | 要渲染的 Sprite 资源 |
color | 应用于 Sprite 的色调颜色(默认值:白色 = 无色调) |
flipX / flipY | 沿轴翻转 Sprite,而不移动 Transform |
drawMode | Simple、Sliced 或 Tiled |
size | 使用 Sliced 或 Tiled 绘制模式时的尺寸 |
sortingLayerName | 渲染器的排序图层名称 |
sortingOrder | 在排序图层中的优先级(数值越低越先渲染) |
maskInteraction | None、Visible Inside Mask 或 Visible Outside Mask |
spriteSortPoint | Center 或 Pivot——决定与相机的排序距离 |
绘制模式:
- Simple(默认):对整个 Sprite 进行等比缩放
- Sliced:用于 9-sliced Sprites;根据 9-slice 区域使用 Width/Height 进行缩放
- Tiled:用于 9-sliced Sprites;平铺中间部分。Tile Mode 选项:Continuous(均匀平铺)或 Adaptive(拉伸至阈值后再平铺)
默认材质:Sprite-Lit-Default(可通过 Material 选择器自定义)
// SpriteRenderer basic usage
SpriteRenderer sr = GetComponent<SpriteRenderer>();
sr.sprite = newSprite;
sr.color = Color.red;
sr.flipX = true;
sr.flipY = true;
sr.sortingLayerName = "Foreground";
sr.sortingOrder = 5;
有关绘制模式示例、Sprite 遮罩和更改回调,请参阅 references/sprites-and-atlas.md。
来源:https://docs.unity3d.com/6000.3/Documentation/ScriptReference/SpriteRenderer.html
Sprite Atlas
Sprite Atlas 是“一种将多个 Sprite 纹理紧密打包到单个纹理(称为图集)中的工具”。这可以减少绘制调用——Unity 对整个图集使用一次绘制调用,而不是为每个 Sprite 单独调用。
创建:Assets > Create > 2D > Sprite Atlas(生成 .spriteatlas 文件)
Sprite Atlas 属性
| 属性 | 描述 |
|---|---|
| 类型 | Master(默认)或 Variant |
| 包含在构建中 | 包含在当前构建中(默认:启用) |
| 允许旋转 | 打包时旋转精灵以最大限度提高密度(默认:启用)。对于 Canvas UI,请禁用 |
| 紧密打包 | 使用精灵轮廓而不是矩形进行打包,以提高打包密度(默认:启用) |
| 边距 | 精灵之间的缓冲空间(默认:4 像素) |
| 启用读写 | 允许脚本访问纹理数据(内存占用翻倍) |
| 生成 Mip Map | 为图集启用 mipmap |
| 过滤模式 | 控制纹理过滤,并覆盖各个精灵的设置 |
| 打包对象 | 要打包到图集中的精灵/文件夹列表 |
运行时 API:「你可以使用 Sprite Atlas API 在项目运行时控制 Sprite Atlas 的加载。」
// Load a sprite from a SpriteAtlas at runtime
using UnityEngine;
using UnityEngine.U2D;
public class AtlasLoader : MonoBehaviour
{
[SerializeField] private SpriteAtlas atlas;
private SpriteRenderer spriteRenderer;
void Start()
{
spriteRenderer = GetComponent<SpriteRenderer>();
Sprite sprite = atlas.GetSprite("player_idle");
spriteRenderer.sprite = sprite;
}
}
延迟绑定:订阅 SpriteAtlasManager.atlasRequested,以按需加载图集(适用于 Addressables/AssetBundle 工作流)。完整的延迟绑定示例请参阅 references/sprites-and-atlas.md。
来源:https://docs.unity3d.com/6000.3/Documentation/Manual/sprite/atlas/atlas-landing.html
Tilemap 系统
Tilemap 可使用瓦片和网格叠加层快速创建 2D 关卡。Tilemap 组件「存储和管理 Tile 资源」,并「将放置在其上的瓦片所需的信息传递给其他相关组件,例如 Tilemap Renderer 和 Tilemap Collider 2D」。
Tilemap 组件属性
| 属性 | 描述 |
|---|---|
| 动画帧速率 | 瓦片动画的播放速度倍率 |
| 颜色 | 应用于所有瓦片的色调(默认:白色) |
| 瓦片锚点 | 瓦片锚点位置的偏移量(以网格单元为单位) |
| 方向 | XY、XZ、YX、YZ、ZX、ZY 或 Custom |
TilemapRenderer 模式
| 模式 | 描述 |
|---|---|
| Chunk | 按位置/纹理对瓦片分组以进行批处理。渲染性能最佳 |
| Individual | 单独渲染每个瓦片。支持与其他渲染器交互和自定义排序 |
| SRP Batch | 兼容 URP 15+。通过顺序批处理对瓦片进行分组 |
其他 TilemapRenderer 属性:
- 排序顺序:渲染期间瓦片的排序方向
- 检测 Chunk 剔除边界:自动或手动(防止精灵被裁剪)
- 材质:用于渲染精灵纹理的材质
- 遮罩交互:无、在遮罩内可见或在遮罩外可见
- 排序图层 / 图层顺序:控制渲染优先级
Tilemap 脚本 API
using UnityEngine;
using UnityEngine.Tilemaps;
Tilemap tilemap = GetComponent<Tilemap>();
// Single tile operations
tilemap.SetTile(new Vector3Int(x, y, 0), tile); // Place tile
tilemap.SetTile(new Vector3Int(x, y, 0), null); // Remove tile
TileBase t = tilemap.GetTile(new Vector3Int(x, y, 0)); // Read tile
// Batch operations (faster than individual SetTile in loops)
tilemap.SetTiles(positionsArray, tilesArray);
tilemap.BoxFill(pos, tile, startX, endX, startY, endY);
tilemap.FloodFill(pos, tile);
tilemap.SwapTile(oldTile, newTile);
// Coordinate conversion
Vector3 worldPos = tilemap.CellToWorld(cellPos);
Vector3Int cellPos = tilemap.WorldToCell(worldPosition);
// Bounds management -- ALWAYS call after procedural generation
tilemap.CompressBounds();
BoundsInt bounds = tilemap.cellBounds;
// Clear
tilemap.ClearAllTiles();
tilemap.RefreshAllTiles();
关键属性:cellBounds、localBounds、size、origin、animationFrameRate
关键事件:tilemapTileChanged、tilemapPositionsChanged、loopEndedForTileAnimation
程序化生成示例、Rule Tiles 和 TilemapCollider2D 设置请参阅 references/tilemaps.md。
来源:https://docs.unity3d.com/6000.3/Documentation/ScriptReference/Tilemaps.Tilemap.html
2D 物理概述
Unity 的 2D 物理系统提供了针对 2D 交互优化的组件。「Unity 的物理系统让你能够处理 2D 物理,从而利用 2D 提供的优化。」
核心组件
| 组件 | 描述 |
|---|---|
| Rigidbody2D | 「允许 GameObject 受模拟重力和其他力影响的组件」 |
| Collider2D | 「用于处理对象物理碰撞的不可见形状」 |
| Physics Material 2D | 控制发生碰撞的 2D 物理对象之间的摩擦和弹性 |
| Constant Force 2D | 为带有 Rigidbody 的 GameObject 添加恒定力或扭矩 |
| Effectors 2D | 控制 GameObject 碰撞体接触时的作用力 |
| 2D Joints | Rigidbody 组件之间的动态连接,可实现受约束的移动 |
Rigidbody2D 关键属性
| 属性 | 描述 |
|---|---|
bodyType | Dynamic、Kinematic 或 Static |
linearVelocity | 位置变化速率(世界单位/秒) |
angularVelocity | 旋转速度(度/秒) |
mass | Rigidbody 的重量 |
gravityScale | 重力影响程度 |
linearDamping | 线性速度阻力 |
angularDamping | 角速度阻力 |
constraints | 冻结各轴上的位置/旋转 |
collisionDetectionMode | Discrete 或 Continuous |
interpolation | None、Interpolate 或 Extrapolate |
Rigidbody2D 关键方法
Rigidbody2D rb = GetComponent<Rigidbody2D>();
// Apply forces
rb.AddForce(Vector2.up * 10f);
rb.AddForce(Vector2.right * 5f, ForceMode2D.Impulse);
rb.AddForceAtPosition(force, position);
rb.AddTorque(15f);
// Move (use in FixedUpdate for physics-safe movement)
rb.MovePosition(rb.position + velocity * Time.fixedDeltaTime);
rb.MoveRotation(rb.rotation + rotationSpeed * Time.fixedDeltaTime);
// Query
rb.Cast(direction, results, distance);
rb.ClosestPoint(worldPoint);
rb.Distance(otherCollider);
rb.GetContacts(contacts);
rb.IsAwake();
rb.IsSleeping();
Physics2D 静态方法(查询)
// Raycast
RaycastHit2D hit = Physics2D.Raycast(origin, direction, distance, layerMask);
RaycastHit2D[] hits = Physics2D.RaycastAll(origin, direction);
// Shape casts
RaycastHit2D boxHit = Physics2D.BoxCast(origin, size, angle, direction, distance);
RaycastHit2D circleHit = Physics2D.CircleCast(origin, radius, direction, distance);
// Overlap detection
Collider2D col = Physics2D.OverlapCircle(point, radius, layerMask);
Collider2D[] cols = Physics2D.OverlapCircleAll(point, radius);
Collider2D boxCol = Physics2D.OverlapBox(point, size, angle, layerMask);
Collider2D pointCol = Physics2D.OverlapPoint(point, layerMask);
// Utilities
float dist = Physics2D.Distance(colliderA, colliderB).distance;
bool touching = Physics2D.IsTouching(colliderA, colliderB);
// 2D platformer: ground check + jump + horizontal movement
Rigidbody2D rb = GetComponent<Rigidbody2D>();
// In Update: ground check and jump
bool isGrounded = Physics2D.OverlapCircle(groundCheck.position, 0.2f, groundLayer);
// Note: Uses legacy Input Manager for simplicity. See unity-input for the new Input System.
if (Input.GetButtonDown("Jump") && isGrounded)
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
// In FixedUpdate: horizontal movement (preserves vertical velocity)
float move = Input.GetAxisRaw("Horizontal");
rb.linearVelocity = new Vector2(move * moveSpeed, rb.linearVelocity.y);
来源:https://docs.unity3d.com/6000.3/Documentation/ScriptReference/Rigidbody2D.html 来源:https://docs.unity3d.com/6000.3/Documentation/ScriptReference/Physics2D.html
2D 光照(URP)
2D 光照需要 Universal Render Pipeline(URP) 和 2D Renderer。使用 2D(URP)模板,或手动配置 URP。
Light 2D 类型
| 类型 | 描述 |
|---|---|
| Global | 照亮目标排序层上的所有对象。不能使用法线贴图 |
| Freeform | 由可编辑顶点定义的自定义形状光源 |
| Sprite | 使用精灵纹理定义光源形状 |
| Spot | 具有方向和角度的锥形光源 |
| Point | 从一个点向所有方向发光 |
Light 2D 属性
| 属性 | 描述 |
|---|---|
| Color | 光源颜色 |
| Intensity | 亮度乘数(可超过 1,以使精灵过亮) |
| Light Order | 渲染队列中的位置(数值越小越先渲染) |
| Overlap Operation | Additive(相加像素值)或 Alpha Blend |
| Target Sorting Layers | 光源只照亮所选排序层上的精灵 |
| Distance | 光源与表面之间的感知距离 |
| Volume Opacity | 体积光照的可见度(0-1) |
| Shadow Intensity | Shadow Caster 2D 遮挡光线的程度(0-1) |
| Normal Maps | 非全局光源类型支持法线贴图 |
using UnityEngine;
using UnityEngine.Rendering.Universal;
public class DayNightCycle : MonoBehaviour
{
[SerializeField] private Light2D globalLight;
[SerializeField] private Color dayColor = Color.white;
[SerializeField] private Color nightColor = new Color(0.1f, 0.1f, 0.3f);
[SerializeField] private float cycleDuration = 60f;
void Update()
{
float t = Mathf.PingPong(Time.time / cycleDuration, 1f);
globalLight.color = Color.Lerp(dayColor, nightColor, t);
globalLight.intensity = Mathf.Lerp(1f, 0.3f, t);
}
}
来源:https://docs.unity3d.com/6000.3/Documentation/Manual/urp/2d-light-properties-explained.html
排序层和顺序
“Sorting Groups 可将带有 Sprite Renderer 的 GameObject 编组,并控制其精灵的渲染顺序。”Unity 会将同一 Sorting Group 中的所有 Sprite Renderer 视为一个统一的渲染单元。
排序层系统
排序层定义总体渲染顺序。在每个层内,Order in Layer(整数)用于设置具体优先级。数值越小越先渲染(显示在数值较大的对象后面)。
Sorting Group 组件
Sorting Group 组件会将子渲染器组织为一个可统一排序的单元。适用场景:
- 复杂的多精灵角色(身体部位使用独立精灵)
- 需要与环境中的对象一起排序的相关对象组
属性:
- Sorting Layer:将该组分配到一个排序层
- Order in Layer:在排序层内的优先级
支持嵌套 Sorting Group:内部组先在组内排序,然后外部组作为一个单元与其他渲染器进行排序。
// Y-sort for top-down games (attach to entities)
void LateUpdate()
{
int order = Mathf.RoundToInt(-transform.position.y * 100);
GetComponent<SpriteRenderer>().sortingOrder = order;
}
// Set sorting layer and order via script
SpriteRenderer sr = GetComponent<SpriteRenderer>();
sr.sortingLayerName = "Characters";
sr.sortingOrder = 10;
sr.sortingLayerID = SortingLayer.NameToID("Characters"); // faster
来源:https://docs.unity3d.com/6000.3/Documentation/Manual/sprite/sorting-group/sorting-group-landing.html
常见模式(C#)
俯视角移动(Rigidbody2D,无重力)
public class TopDownMovement : MonoBehaviour
{
[SerializeField] private float moveSpeed = 5f;
private Rigidbody2D rb;
private Vector2 moveInput;
void Awake() { rb = GetComponent<Rigidbody2D>(); rb.gravityScale = 0f; }
void Update() // legacy Input; see unity-input
{
moveInput = new Vector2(Input.GetAxisRaw("Horizontal"),
Input.GetAxisRaw("Vertical")).normalized;
}
void FixedUpdate()
{
rb.MovePosition(rb.position + moveInput * moveSpeed * Time.fixedDeltaTime);
}
}
精灵方向翻转 / 摄像机跟随 / Tilemap 点击
// Flip sprite based on movement direction (legacy Input; see unity-input)
float h = Input.GetAxisRaw("Horizontal");
if (h != 0) spriteRenderer.flipX = h < 0;
// Simple 2D camera follow (attach to Camera, set offset.z = -10)
void LateUpdate()
{
Vector3 desired = target.position + offset;
transform.position = Vector3.Lerp(transform.position, desired, smoothSpeed * Time.deltaTime);
}
// Place tile at mouse click
Vector3 worldPos = cam.ScreenToWorldPoint(Input.mousePosition);
Vector3Int cellPos = tilemap.WorldToCell(worldPos);
tilemap.SetTile(cellPos, tileToPlace);
反模式
-
在 2D 游戏中使用 3D 物理:始终使用 Rigidbody2D 和 Collider2D,绝不要使用 Rigidbody/BoxCollider。2D 物理引擎是独立的,并针对 2D 进行了优化。
-
使用 Transform 移动 Rigidbody2D:绝不要使用
transform.position移动物理对象。请在 FixedUpdate 中使用Rigidbody2D.MovePosition(),或使用AddForce()。直接操作 Transform 会绕过物理模拟并破坏碰撞检测。 -
运行时使用 Transform.localScale 缩放精灵:改用 Sliced/Tiled 绘制模式下的
SpriteRenderer.size。Transform 缩放会导致碰撞体出现问题,且性能较低。 -
忘记对程序化 Tilemap 调用 CompressBounds():以程序方式生成瓦片后,调用
tilemap.CompressBounds()重新计算边界。否则,遍历cellBounds时会包含空白区域。 -
每个精灵都产生一次绘制调用(未使用图集):将相关精灵打包到 Sprite Atlas 中。如果不使用图集,每个不同的纹理都会触发一次单独的绘制调用。
-
不必要地为 Sprite Atlas 启用 Read/Write:这会使内存使用量翻倍。只有在需要通过
Texture2D.SetPixels进行脚本访问时才启用。 -
对 UI 精灵启用 Allow Rotation:打包 Canvas UI 中使用的精灵时,请在 Sprite Atlas 设置中禁用 Allow Rotation,因为旋转会破坏 UI 布局。
-
未正确设置 TilemapRenderer 模式:静态 tilemap 使用 Chunk 模式(性能最佳)。只有当瓦片需要与其他渲染器交互或需要自定义排序时,才使用 Individual 模式。
-
到处使用连续碰撞检测:仅对快速移动的对象将
collisionDetectionMode设为 Continuous。对于大多数 2D 对象,Discrete 的开销更低且已足够。 -
忽略 Sorting Layers:仅依赖 Order in Layer 会导致使用难以理解的魔法数字。定义有意义的 Sorting Layers(Background、Midground、Characters、Foreground、UI),并使用 Order in Layer 在各图层内微调顺序。
关键 API 速查
| 类 | 关键成员 |
|---|---|
SpriteRenderer | .sprite, .color, .flipX, .flipY, .drawMode, .size, .sortingLayerName, .sortingOrder |
SpriteAtlas | .GetSprite(name), .GetSprites(sprites[]), SpriteAtlasManager.atlasRequested |
Tilemap | .SetTile(), .GetTile(), .SetTiles(), .ClearAllTiles(), .BoxFill(), .FloodFill(), .SwapTile(), .WorldToCell(), .CellToWorld(), .CompressBounds(), .cellBounds |
Rigidbody2D | .linearVelocity, .angularVelocity, .AddForce(), .MovePosition(), .MoveRotation(), .Cast(), .bodyType, .gravityScale, .mass |
Physics2D | .Raycast(), .BoxCast(), .CircleCast(), .OverlapCircle(), .OverlapBox(), .OverlapPoint(), .IsTouching() |
Light2D | .color, .intensity, .lightType(需要 UnityEngine.Rendering.Universal) |
SortingGroup | .sortingLayerName, .sortingOrder |
相关技能
- unity-foundations —— GameObjects、Components、Transforms、Prefabs、ScriptableObjects
- unity-physics —— 深入了解 3D/2D 物理、关节、射线检测、物理材质
- unity-graphics —— 渲染管线、材质、着色器、后期处理
- unity-lighting-vfx —— URP 光照设置、视觉效果、粒子系统