【Unity Tilemap】教程 | Basic、Rule Tile、Prefab Brush、Tilemap Collider

本合集提供B站UP主圈毛君的Unity Tilemap系列教程链接,包括基本概念、规则瓷砖、预置画刷及碰撞器设置等,适合初学者快速掌握Unity Tilemap使用技巧。
<think>我们之前已经决定创建自定义的Tile类(SimpleTile)来替代直接使用UnityTile类。这样我们可以直接访问sprite属性,避免类型转换问题。 需要修改和添加的脚本如下: 1. 添加自定义Tile类(SimpleTile.cs) 2. 修改TerrainConfig.cs,将其中的TileBase或Tile字段改为我们自定义的SimpleTile类型 3. 修改GridManager.cs,在放置地形对象时,直接从TerrainConfig中获取自定义Tile的sprite 4. 修改TerrainObject.cs,使其接受Sprite进行初始化 5. 在Unity编辑器中,将之前使用的Tile资源替换为我们自定义的SimpleTile资源 下面我们详细说明每个步骤:</think># 创建自定义 Tile 类的完整指南 我将为您提供创建自定义 Tile 类的详细步骤和完整代码实现,包括所有必要的脚本修改和 Unity 编辑器设置。 ## 需要创建和修改的脚本 ### 1. 创建自定义 Tile 基类 (`CustomTile.cs`) ```csharp using UnityEngine; using UnityEngine.Tilemaps; namespace gridstudy { [CreateAssetMenu(fileName = "CustomTile", menuName = "Tiles/Custom Tile")] public class CustomTile : TileBase { [Header("Base Properties")] public Sprite sprite; public Color color = Color.white; public Tile.ColliderType colliderType = Tile.ColliderType.Sprite; [Header("Game Properties")] public int movementCost = 1; public bool isWalkable = true; public bool isBuildable = false; public override void GetTileData(Vector3Int position, ITilemap tilemap, ref TileData tileData) { tileData.sprite = sprite; tileData.color = color; tileData.colliderType = colliderType; tileData.flags = TileFlags.LockAll; } public override bool GetTileAnimationData(Vector3Int position, ITilemap tilemap, ref TileAnimationData tileAnimationData) { return false; // 默认不实现动画 } // 添加自定义逻辑的方法 public virtual void OnUnitEnter(Vector3Int position) { } public virtual void OnUnitExit(Vector3Int position) { } } } ``` ### 2. 创建地形配置类 (`TerrainConfig.cs`) ```csharp using UnityEngine; namespace gridstudy { [CreateAssetMenu(menuName = "Terrain/TerrainConfig")] public class TerrainConfig : ScriptableObject { public TerrainType type; public CustomTile tile; // 使用自定义 Tile 类 // 添加获取 Sprite 的属性 public Sprite Sprite => tile != null ? tile.sprite : null; // 添加游戏属性访问器 public int MovementCost => tile != null ? tile.movementCost : 1; public bool IsWalkable => tile != null ? tile.isWalkable : true; public bool IsBuildable => tile != null ? tile.isBuildable : false; } } ``` ### 3. 修改 `GridManager.cs` ```csharp // ... 其他代码保持不变 ... public class GridManager : MonoBehaviour { // ... [SerializeField] 字段保持不变 ... // 添加获取 Tile 属性的方法 public CustomTile GetTileAtPosition(Vector2Int gridPos) { GridCell cell = GetCellData(gridPos); if (cell == null || cell.terrain == null) return null; TerrainConfig config = _config.GetTerrainConfig(cell.terrain.type); return config?.tile; } // 修改 PlaceObject 方法 public void PlaceObject<T>(GridObjectType type, Vector2Int gridPos, T data) where T : ScriptableObject { // ... 前面的代码保持不变 ... switch (type) { case GridObjectType.Terrain: cell.terrain = data as TerrainData; var terrainObj = instance.GetComponent<TerrainObject>(); if (terrainObj != null) { TerrainConfig config = _config.GetTerrainConfig(cell.terrain.type); terrainObj.Initialize(cell.terrain, config?.Sprite); } // 更新 Tilemap UpdateTileAtPosition(gridPos, config?.tile); break; // ... 其他 case 保持不变 ... } // ... 后面的代码保持不变 ... } // 添加 Tilemap 更新方法 private void UpdateTileAtPosition(Vector2Int gridPos, CustomTile tile) { if (_terrainTilemap == null) return; Vector3Int tilePos = new Vector3Int(gridPos.x, gridPos.y, 0); _terrainTilemap.SetTile(tilePos, tile); } } ``` ### 4. 修改 `TerrainObject.cs` ```csharp using UnityEngine; namespace gridstudy { public class TerrainObject : GridObject { [SerializeField] private SpriteRenderer _renderer; public TerrainData Data { get; private set; } public void Initialize(TerrainData data, Sprite sprite) { Data = data; if (_renderer != null && sprite != null) { _renderer.sprite = sprite; // 根据地形类型调整排序 _renderer.sortingOrder = (int)data.type; } } private void Awake() { ObjectType = GridObjectType.Terrain; if (_renderer == null) _renderer = GetComponentInChildren<SpriteRenderer>(); } } } ``` ### 5. 创建地形数据类 (`TerrainData.cs`) ```csharp using UnityEngine; namespace gridstudy { [CreateAssetMenu(menuName = "Terrain/TerrainData")] public class TerrainData : ScriptableObject { public TerrainType type; [TextArea] public string description; // 可以添加更多游戏特定属性 public bool canSpawnResources = false; public int resourceSpawnChance = 10; } } public enum TerrainType { Grass, Water, Sand, Mountain, Forest, Snow, Lava } ``` ## Unity 编辑器设置步骤 ### 1. 创建自定义 Tile 资源 1. 在 Project 窗口右键:"Create" > "Tiles" > "Custom Tile" 2. 创建不同地形类型的 Tile: - GrassTile - WaterTile - SandTile - MountainTile - ForestTile 3. 配置每个 Tile 的属性: - **Sprite**: 选择对应的精灵图 - **Color**: 根据需要调整颜色 - **Collider Type**: 设置碰撞体类型 - **Movement Cost**: 设置移动消耗 - **Is Walkable**: 是否可通行 - **Is Buildable**: 是否可建造 ### 2. 创建地形配置资源 1. 在 Project 窗口右键:"Create" > "Terrain" > "TerrainConfig" 2. 创建与地形类型对应的配置: - GrassConfig - WaterConfig - SandConfig - MountainConfig - ForestConfig 3. 配置每个地形: - **Type**: 选择对应的地形类型 - **Tile**: 拖入对应的自定义 Tile 资源 ### 3. 创建地形数据资源 1. 在 Project 窗口右键:"Create" > "Terrain" > "TerrainData" 2. 创建与地形类型对应的数据: - GrassData - WaterData - SandData - MountainData - ForestData 3. 配置每个地形数据: - **Type**: 选择对应的地形类型 - **Description**: 添加描述 - 设置其他游戏特定属性 ### 4. 配置 GridManager 1. 在 Hierarchy 中选择 GridManager 对象 2. 在 Inspector 中: - 设置 **Config** 引用到 GridConfig 资源 - 设置 **Terrain Tilemap** 引用到场景中的 Tilemap 对象 - 设置 **Default Tile** 为 GrassTile 或其他默认 Tile ### 5. 配置 GridConfig 资源 1. 打开 GridConfig 资源 2. 设置: - **Terrain Prefab**: 地形对象的预制体 - **Structure Prefab**: 建筑对象的预制体 - **Chess Prefab**: 棋子对象的预制体 - **Token Prefab**: 标记对象的预制体 3. 添加地形配置映射: ```csharp using System.Collections.Generic; using UnityEngine; namespace gridstudy { [CreateAssetMenu(menuName = "Grid/GridConfig")] public class GridConfig : ScriptableObject { [Header("Prefabs")] public GameObject TerrainPrefab; public GameObject StructurePrefab; public GameObject ChessPrefab; public GameObject TokenPrefab; [Header("Terrain Configurations")] public List<TerrainConfig> terrainConfigs = new List<TerrainConfig>(); // 添加获取地形配置的方法 public TerrainConfig GetTerrainConfig(TerrainType type) { return terrainConfigs.Find(config => config.type == type); } } } ``` ## 自定义 Tile 的高级用法 ### 1. 创建动画 Tile ```csharp [CreateAssetMenu(fileName = "AnimatedTile", menuName = "Tiles/Animated Tile")] public class AnimatedTile : CustomTile { public Sprite[] animationSprites; public float animationSpeed = 1f; public float animationStartTime; public override bool GetTileAnimationData(Vector3Int position, ITilemap tilemap, ref TileAnimationData tileAnimationData) { if (animationSprites == null || animationSprites.Length == 0) return false; tileAnimationData.animatedSprites = animationSprites; tileAnimationData.animationSpeed = animationSpeed; tileAnimationData.animationStartTime = animationStartTime; return true; } } ``` ### 2. 创建规则 Tile ```csharp [CreateAssetMenu(fileName = "RuleBasedTile", menuName = "Tiles/Rule Based Tile")] public class RuleBasedTile : CustomTile { [System.Serializable] public class TileRule { public Sprite sprite; public Vector3Int[] neighbors; } public TileRule[] rules; public override void GetTileData(Vector3Int position, ITilemap tilemap, ref TileData tileData) { // 简化版规则匹配 - 实际中应使用更复杂的匹配逻辑 foreach (var rule in rules) { bool match = true; foreach (var offset in rule.neighbors) { Vector3Int neighborPos = position + offset; TileBase neighborTile = tilemap.GetTile(neighborPos); // 简单的匹配逻辑 - 实际中需要更复杂的规则 if (neighborTile == null) { match = false; break; } } if (match) { tileData.sprite = rule.sprite; tileData.color = color; tileData.colliderType = colliderType; return; } } // 没有匹配规则时使用默认 sprite tileData.sprite = sprite; tileData.color = color; tileData.colliderType = colliderType; } } ``` ### 3. 创建交互式 Tile ```csharp [CreateAssetMenu(fileName = "InteractiveTile", menuName = "Tiles/Interactive Tile")] public class InteractiveTile : CustomTile { public GameObject interactionEffect; public override void OnUnitEnter(Vector3Int position) { base.OnUnitEnter(position); if (interactionEffect != null) { Vector3 worldPos = GridManager.Instance.GridToWorld(new Vector2Int(position.x, position.y)); Instantiate(interactionEffect, worldPos, Quaternion.identity); } Debug.Log($"Unit entered {name} at position {position}"); } } ``` ## 场景设置和工作流程 ### 1. 场景层级结构 ``` Grid (Grid 组件) ├── TerrainTilemap (TilemapTilemap Renderer) ├── ObjectLayer (Tilemap 用于放置游戏对象) └── GridManager (空对象,附加 GridManager 脚本) ``` ### 2. 工作流程 1. **初始化网格**: ```csharp void Start() { _gridManager.GenerateGrid(20, 15); } ``` 2. **生成地形**: ```csharp public void GenerateRandomTerrain() { for (int x = 0; x < _gridManager.GridWidth; x++) { for (int y = 0; y < _gridManager.GridHeight; y++) { TerrainType type = GetRandomTerrainType(x, y); TerrainData data = GetTerrainDataForType(type); _gridManager.PlaceObject(GridObjectType.Terrain, new Vector2Int(x, y), data); } } } ``` 3. **交互示例**: ```csharp public void OnUnitMoved(Vector2Int from, Vector2Int to) { CustomTile tile = _gridManager.GetTileAtPosition(to); if (tile != null) { tile.OnUnitEnter(new Vector3Int(to.x, to.y, 0)); } } ``` ## 常见问题解决方案 ### 问题:Tile 显示为粉红色 - **原因**:精灵图丢失或未正确分配 - **解决**: 1. 检查 CustomTile 资源中的 Sprite 字段 2. 确保精灵图已导入项目 3. 在 Inspector 中重新分配精灵图 ### 问题:碰撞检测不工作 - **原因**:未正确设置碰撞体类型 - **解决**: 1. 在 CustomTile 中设置 Collider Type 2. 确保 TilemapTilemap Collider 2D 组件 3. 检查物理设置:Edit > Project Settings > Physics 2D ### 问题:地形覆盖顺序错误 - **原因**:排序层设置不正确 - **解决**: 1. 在 Tilemap Renderer 组件中设置 Sorting Layer 和 Order in Layer 2. 在 TerrainObject 中根据地形类型设置 sortingOrder: ```csharp _renderer.sortingOrder = (int)data.type * 10; // 按类型增加排序层级 ``` ## 总结 创建自定义 Tile 类需要以下步骤: 1. **创建核心脚本**: - `CustomTile.cs` - 自定义 Tile 基类 - `TerrainConfig.cs` - 地形配置 - `TerrainData.cs` - 地形数据 - 修改 `GridManager.cs` 和 `TerrainObject.cs` 2. **Unity 编辑器设置**: - 创建 CustomTile 资源 - 创建 TerrainConfig 资源 - 创建 TerrainData 资源 - 配置 GridManager 和 GridConfig 3. **高级功能扩展**: - 动画 Tile - 规则 Tile - 交互式 Tile 这种自定义 Tile 系统提供了极大的灵活性,使您能够轻松扩展游戏功能,同时保持代码的整洁和可维护性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值