You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Unity中如何修改AnimatedTile的动画速度并让Tilemap内现有瓦片生效?

Unity中如何修改AnimatedTile的动画速度并让Tilemap内现有瓦片生效?

嘿,我来给你捋捋怎么解决这个问题!你现在是想在Unity运行的时候,动态调整Tilemap里AnimatedTile的动画速度,而且要让已经铺好的瓦片立刻用上新速度对吧?之前你尝试用Resources.Load<AnimatedTile>来操作,应该是卡在了怎么让现有瓦片生效这一步吧?

其实这里有两个核心关键点:一是怎么修改AnimatedTile的速度参数,二是怎么让Tilemap里的现有瓦片感知到参数变化并刷新。我给你分享两个实用的方案:

方案一:用反射修改原生AnimatedTile的参数

原生的AnimatedTile里,m_MinSpeedm_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

火山引擎 最新活动