如何以编程方式在 Unity2D 中切换瓷砖调色板
How to programmatically switch tile palettes in Unity2D
场景:用户每个季节(夏季、秋季等)都有不同的瓷砖调色板,如果瓷砖集中的瓷砖数量大于 5 或 10,则使用流行的 Unity 技术在两者之间切换会很乏味。所述用户如何以编程方式在他们的瓷砖调色板之间切换,而不是使用预制瓷砖等浪费的解决方案?
这个问题似乎很严重,Unity 文档会涵盖它。然而,我发现自己通过多年的论坛帖子来挖掘我的解决方案。这是我想出的,并不太复杂。
创建您的图块集。将您的图块集导入为多精灵精灵表,并使用 Unity 精灵编辑器拆分它们。不要为每个精灵命名。每个 tileset 应该以完全相同的方式组织(bushes/trees/objects 应该在每个季节的 tilesheet 上的相同位置)。完成后,在“Assets”文件夹中创建一个文件夹“Resources”。在资源内部,创建一个文件夹“Spritesheets”,并将您的 spricesheet 放入其中。
运行 这个重命名脚本:
using UnityEngine;
using UnityEditor;
using System.Collections;
public class SpriteRenamer : MonoBehaviour
{
public Texture2D[] texture2Ds;
public string newName;
private string path;
private TextureImporter textureImporter;
void Start ()
{
foreach(Texture2D texture2D in texture2Ds){
path = AssetDatabase.GetAssetPath (texture2D);
textureImporter = AssetImporter.GetAtPath (path) as TextureImporter;
SpriteMetaData[] sliceMetaData = textureImporter.spritesheet;
int index = 0;
foreach (SpriteMetaData individualSliceData in sliceMetaData)
{
sliceMetaData[index].name = string.Format (newName + "_{0}", index);
print (sliceMetaData[index].name);
index++;
}
textureImporter.spritesheet = sliceMetaData;
EditorUtility.SetDirty (textureImporter);
textureImporter.SaveAndReimport ();
AssetDatabase.ImportAsset (path, ImportAssetOptions.ForceUpdate);
}
}
}
将它附加到空场景中的空游戏对象(只是为了简单起见)。将您的 spritesheet 拖放到 Texture2D 数组中。将 newName
字段设置为您想要的任何值,它将成为每个 spritesheet 中每个 sprite 名称的前缀。最后,运行 场景和每个 spritesheet 的 sprite 将被重命名,使每个对应的 sprite 具有相同的名称。
- 我们现在修改了每个季节的图块表,因此每个图块都具有相同的名称。下一步是创建一个带有子 TilePalette 的 Grid 对象。绘制所有风景、碰撞等。您可以根据需要使用任意数量的 TilePalettes,只要它们是 Grid 对象的子对象即可。现在,创建一个名为 ReskinnableTileBase 的脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
public class ReskinnableTileBase : TileBase
{
public Sprite sprite;
public override void GetTileData(Vector3Int position, ITilemap tilemap, ref TileData tileData)
{
tileData.sprite = sprite;
}
}
- 将此 Reskinner 脚本附加到您的网格对象:
using System;
using System.Linq;
using UnityEngine;
using UnityEngine.Tilemaps;
public class Reskinner : MonoBehaviour
{
Sprite[] subSprites;
Tilemap[] tilemaps;
void Start(){
tilemaps = GetComponentsInChildren<Tilemap>();
SetSkin("#INSERT DEFAULT TILE PALETTE NAME HERE#");
}
public void SetSkin(string name){
reloadSprites(name);
foreach(Tilemap tilemap in tilemaps){
for(int x = (int)tilemap.localBounds.min.x; x < tilemap.localBounds.max.x; x++){
for(int y = (int)tilemap.localBounds.min.y; y < tilemap.localBounds.max.y; y++){
TileBase tb = tilemap.GetTile(new Vector3Int(x, y, 0));
Debug.Log(tb);
ReskinnableTileBase rtb = (ReskinnableTileBase)ScriptableObject.CreateInstance(typeof(ReskinnableTileBase));
if(tb == null || rtb == null || tb.name.Length < 1){
continue;
}
Sprite replace = getSubSpriteByName(tb.name);
rtb.sprite = replace;
rtb.name = tb.name;
tilemap.SwapTile(tb, (TileBase)rtb);
}
}
}
}
void reloadSprites(string name){
subSprites = Resources.LoadAll<Sprite>("Spritesheets/" + name);
}
Sprite getSubSpriteByName(string name){
foreach(Sprite s in subSprites){
if(s.name == name){
return s;
}
}
return null;
}
}
- 好了!现在,任何时候您需要更改 skin/season/tilesheet,只需使用对 Grid 的
Reskinner
脚本的引用,然后调用 SetSkin
方法,如下所示:
Reskinner reskinner = gridObject.GetComponent<Reskinner>();
reskinner.SetSkin("summer");
场景:用户每个季节(夏季、秋季等)都有不同的瓷砖调色板,如果瓷砖集中的瓷砖数量大于 5 或 10,则使用流行的 Unity 技术在两者之间切换会很乏味。所述用户如何以编程方式在他们的瓷砖调色板之间切换,而不是使用预制瓷砖等浪费的解决方案?
这个问题似乎很严重,Unity 文档会涵盖它。然而,我发现自己通过多年的论坛帖子来挖掘我的解决方案。这是我想出的,并不太复杂。
创建您的图块集。将您的图块集导入为多精灵精灵表,并使用 Unity 精灵编辑器拆分它们。不要为每个精灵命名。每个 tileset 应该以完全相同的方式组织(bushes/trees/objects 应该在每个季节的 tilesheet 上的相同位置)。完成后,在“Assets”文件夹中创建一个文件夹“Resources”。在资源内部,创建一个文件夹“Spritesheets”,并将您的 spricesheet 放入其中。
运行 这个重命名脚本:
using UnityEngine;
using UnityEditor;
using System.Collections;
public class SpriteRenamer : MonoBehaviour
{
public Texture2D[] texture2Ds;
public string newName;
private string path;
private TextureImporter textureImporter;
void Start ()
{
foreach(Texture2D texture2D in texture2Ds){
path = AssetDatabase.GetAssetPath (texture2D);
textureImporter = AssetImporter.GetAtPath (path) as TextureImporter;
SpriteMetaData[] sliceMetaData = textureImporter.spritesheet;
int index = 0;
foreach (SpriteMetaData individualSliceData in sliceMetaData)
{
sliceMetaData[index].name = string.Format (newName + "_{0}", index);
print (sliceMetaData[index].name);
index++;
}
textureImporter.spritesheet = sliceMetaData;
EditorUtility.SetDirty (textureImporter);
textureImporter.SaveAndReimport ();
AssetDatabase.ImportAsset (path, ImportAssetOptions.ForceUpdate);
}
}
}
将它附加到空场景中的空游戏对象(只是为了简单起见)。将您的 spritesheet 拖放到 Texture2D 数组中。将 newName
字段设置为您想要的任何值,它将成为每个 spritesheet 中每个 sprite 名称的前缀。最后,运行 场景和每个 spritesheet 的 sprite 将被重命名,使每个对应的 sprite 具有相同的名称。
- 我们现在修改了每个季节的图块表,因此每个图块都具有相同的名称。下一步是创建一个带有子 TilePalette 的 Grid 对象。绘制所有风景、碰撞等。您可以根据需要使用任意数量的 TilePalettes,只要它们是 Grid 对象的子对象即可。现在,创建一个名为 ReskinnableTileBase 的脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
public class ReskinnableTileBase : TileBase
{
public Sprite sprite;
public override void GetTileData(Vector3Int position, ITilemap tilemap, ref TileData tileData)
{
tileData.sprite = sprite;
}
}
- 将此 Reskinner 脚本附加到您的网格对象:
using System;
using System.Linq;
using UnityEngine;
using UnityEngine.Tilemaps;
public class Reskinner : MonoBehaviour
{
Sprite[] subSprites;
Tilemap[] tilemaps;
void Start(){
tilemaps = GetComponentsInChildren<Tilemap>();
SetSkin("#INSERT DEFAULT TILE PALETTE NAME HERE#");
}
public void SetSkin(string name){
reloadSprites(name);
foreach(Tilemap tilemap in tilemaps){
for(int x = (int)tilemap.localBounds.min.x; x < tilemap.localBounds.max.x; x++){
for(int y = (int)tilemap.localBounds.min.y; y < tilemap.localBounds.max.y; y++){
TileBase tb = tilemap.GetTile(new Vector3Int(x, y, 0));
Debug.Log(tb);
ReskinnableTileBase rtb = (ReskinnableTileBase)ScriptableObject.CreateInstance(typeof(ReskinnableTileBase));
if(tb == null || rtb == null || tb.name.Length < 1){
continue;
}
Sprite replace = getSubSpriteByName(tb.name);
rtb.sprite = replace;
rtb.name = tb.name;
tilemap.SwapTile(tb, (TileBase)rtb);
}
}
}
}
void reloadSprites(string name){
subSprites = Resources.LoadAll<Sprite>("Spritesheets/" + name);
}
Sprite getSubSpriteByName(string name){
foreach(Sprite s in subSprites){
if(s.name == name){
return s;
}
}
return null;
}
}
- 好了!现在,任何时候您需要更改 skin/season/tilesheet,只需使用对 Grid 的
Reskinner
脚本的引用,然后调用SetSkin
方法,如下所示:
Reskinner reskinner = gridObject.GetComponent<Reskinner>();
reskinner.SetSkin("summer");