Unity中如何修改AnimatedTile的动画速度并让Tilemap内现有瓦片生效?
嘿,我来给你捋捋怎么解决这个问题!你现在是想在Unity运行的时候,动态调整Tilemap里AnimatedTile的动画速度,而且要让已经铺好的瓦片立刻用上新速度对吧?之前你尝试用Resources.Load<AnimatedTile>来操作,应该是卡在了怎么让现有瓦片生效这一步吧?
其实这里有两个核心关键点:一是怎么修改AnimatedTile的速度参数,二是怎么让Tilemap里的现有瓦片感知到参数变化并刷新。我给你分享两个实用的方案:
方案一:用反射修改原生AnimatedTile的参数
原生的AnimatedTile里,m_MinSpeed和m_MaxSpeed是私有字段,没法直接访问,所以我们可以用反射来修改它们的值。修改完参数后,必须强制刷新Tilemap里的对应瓦片,不然已经初始化的瓦片不会自动读取新参数。
你可以试试写这样一个方法:
// 记得在Inspector面板里给这两个变量赋值 public Tilemap targetTilemap; public AnimatedTile myAnimatedTile; public void UpdateAnimatedTileSpeed(float newMinSpeed, float newMaxSpeed) { // 第一步:通过反射修改AnimatedTile的私有速度字段 var minSpeedField = typeof(AnimatedTile).GetField("m_MinSpeed", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); var maxSpeedField = typeof(AnimatedTile).GetField("m_MaxSpeed", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); minSpeedField.SetValue(myAnimatedTile, newMinSpeed); maxSpeedField.SetValue(myAnimatedTile, newMaxSpeed); // 第二步:遍历Tilemap,重置对应瓦片触发参数更新 BoundsInt tileBounds = targetTilemap.cellBounds; TileBase[] allTilesInMap = targetTilemap.GetTilesBlock(tileBounds); for (int x = 0; x < tileBounds.size.x; x++) { for (int y = 0; y < tileBounds.size.y; y++) { int tileIndex = x + y * tileBounds.size.x; TileBase currentTile = allTilesInMap[tileIndex]; // 找到所有使用目标AnimatedTile的位置 if (currentTile == myAnimatedTile) { Vector3Int tilePos = new Vector3Int(tileBounds.x + x, tileBounds.y + y, tileBounds.z); // 先设为空再重新放置,让瓦片重新读取新的速度参数 targetTilemap.SetTile(tilePos, null); targetTilemap.SetTile(tilePos, myAnimatedTile); } } } // 最后强制刷新整个Tilemap,确保渲染同步更新 targetTilemap.RefreshAllTiles(); }
为什么要重新设置瓦片?因为AnimatedTile的动画逻辑是在瓦片被放置到Tilemap时初始化的,修改参数后不重置的话,已经初始化的瓦片不会主动读取新的速度值,所以必须触发一次重新初始化。
方案二:自定义AnimatedTile类(更推荐)
如果不想用反射(毕竟反射可能存在性能或兼容性隐患),你可以自己写一个继承自AnimatedTile的自定义类,把速度字段暴露成可直接访问的属性,修改起来会更安全直观。
比如:
using UnityEngine; using UnityEngine.Tilemaps; // 这样你可以在Unity的CreateAsset菜单里直接创建这个自定义瓦片 [CreateAssetMenu(fileName = "CustomAnimatedTile", menuName = "Tiles/Custom Animated Tile")] public class CustomAnimatedTile : AnimatedTile { // 直接暴露Min和MaxSpeed的属性,不用碰私有字段 public float MinSpeed { get => m_MinSpeed; set => m_MinSpeed = value; } public float MaxSpeed { get => m_MaxSpeed; set => m_MaxSpeed = value; } }
之后你就可以直接通过customAnimatedTile.MinSpeed = 0.5f;这种方式修改速度,完全不用反射。刷新Tilemap的步骤和方案一一样,重置对应瓦片再调用RefreshAllTiles()就可以了。
按照上面的方法操作后,Tilemap里所有用这个AnimatedTile的瓦片都会立刻用上新的动画速度啦!
备注:内容来源于stack exchange,提问作者Robin




