Tipos de tile personalizados
Esta página documenta código interno del motor disponible exclusivamente para los licenciatarios de las ediciones Source y Studio.

Los tiles también son datos: el generador de abajo escribe los mismos assets de tilemap que pintarías a mano.
MCE usa el sistema Tilemap de Unity con una capa de datos personalizada que asocia cada asset de tile con un tipo de movimiento y un escenario de batalla. Esta página cubre la arquitectura del sistema de tiles y cómo extenderlo con comportamientos de tile personalizados.
Descripción general de la arquitectura
El sistema de tiles tiene tres capas:
- El enum
TileType: define la semántica de movimiento para elGridController. TileData/SingleTileData: una base de datos ScriptableObject que asocia cada assetTileBasecon unTileTypey unBattleScenario.- Comportamientos de tile: componentes MonoBehaviour colocados en los GameObjects de los tiles que implementan
ICharacterInteractingTileoITileTypeOverridepara agregar lógica en tiempo de ejecución.
TileBase (Unity asset)
└─ registered in TileData ─► SingleTileData { Tile, TileType, BattleScenario }
└─ instantiated object ─► MonoBehaviour(s) implementing ICharacterInteractingTile
El enum TileType
Ubicado en Assets/OpenMon/Core/Runtime/World/TileType.cs:
public enum TileType
{
NonExistent, // Tile has no data -- treated as void
Walkable, // Normal ground the player can traverse
NonWalkable, // Solid obstacle (walls, trees, rocks)
Jumpable, // Ledge the player can jump over (one-way)
Bridge, // Bridge surface (layered above water)
BridgeEntrance, // Transition tile between ground and bridge
Water, // Swimmable/surfable water
Waterfall, // Vertical water the player can climb
Slippery, // Ice -- forces movement until hitting an obstacle
WalkableNotBikable // Walkable on foot but not on a bicycle
}
GridController.GetTypeOfTileDirectlyBelowSortOrder() resuelve el tipo efectivo de cualquier posición del mundo recorriendo los tilemaps del orden de ordenación más alto al más bajo, comprobando primero los componentes ITileTypeOverride y recurriendo después a la consulta en TileData.
Agregar un nuevo valor de TileType
- Agrega tu valor al enum
TileType(p. ej.,Quicksand). - Gestiónalo en la lógica de movimiento de
MCECharacterController(los bloques switch/if que ramifican según el tipo de tile). - Registra los tiles de ese tipo en el asset
TileDatamediante el Inspector.
El sistema TileData
TileData (Assets/OpenMon/Core/Runtime/World/TileData.cs) es un ScriptableObject que contiene todos los tiles del proyecto:
[CreateAssetMenu(menuName = "MCE/Maps/TileData", fileName = "TileData")]
public class TileData : OpenMonScriptable<TileData>
{
[SerializeField]
private List<SingleTileData> TileDataCollection = new();
}
Cada entrada es un SingleTileData:
[Serializable]
public class SingleTileData
{
public TileBase Tile; // Reference to the Unity tile asset
public TileType Type; // Movement semantics
public BattleScenario BattleScenario; // Visual theme for battles on this tile
}
Utilidades de editor
TileData expone varios botones en el Inspector (mediante [Button] de NovaInspector):
| Botón | Propósito |
|---|---|
| AddGroup | Agrega por lotes una lista de tiles con el mismo tipo y escenario de batalla |
| Populate | Busca en el proyecto todos los assets TileBase y agrega los que falten (marcados como NonExistent) |
| CheckInvalid | Registra errores para los tiles que siguen marcados como NonExistent o que no tienen BattleScenario |
| RemoveColliders | Quita los colisionadores físicos de todas las entradas RuleTile (MCE usa su propia colisión de cuadrícula) |
| RemoveNulls | Limpia las entradas cuyo asset de tile fue eliminado |
Rendimiento de la consulta
TileData usa una caché Dictionary<TileBase, SingleTileData> que se rellena en el primer acceso. Los tiles desconocidos registran una advertencia una sola vez (mediante missingTileCache) y se tratan como transitables.
SiblingTile (autotile con vecinos conectados)
SiblingTile (Assets/OpenMon/Core/Runtime/World/Tiles/SiblingTile.cs) extiende el RuleTile de Unity para soportar tiles que se conectan visualmente con otros tipos de tile, por ejemplo, un tile de hierba que se funde con tierra, o un camino que se une con tiles de carretera.
[CreateAssetMenu(menuName = "2D/Tiles/SiblingTile", fileName = "SiblingTile")]
public class SiblingTile : RuleTile<SiblingTile.Neighbor>
{
[SerializeField]
private List<TileBase> Siblings = new();
[SerializeField]
private bool DefaultIncludesSibling = true;
public class Neighbor : RuleTile.TilingRule.Neighbor
{
public const int Sibling = 3; // Custom neighbor constant
}
}
Cómo funciona
SiblingTile agrega un tercer modo de coincidencia de vecinos además de los integrados de Unity, "This" y "Not This":
| Valor de vecino | Significado |
|---|---|
Sibling (3) | Coincide si el tile adyacente está en la lista Siblings |
Not This (2) | Cuando DefaultIncludesSibling es true, también excluye a los hermanos |
| Por defecto (1 / otro) | Cuando DefaultIncludesSibling es true, los hermanos también coinciden como "This" |
La sobrescritura de RuleMatch:
public override bool RuleMatch(int neighbor, TileBase tile) =>
neighbor switch
{
Neighbor.Sibling => Siblings.Contains(tile),
2 => DefaultIncludesSibling && !Siblings.Contains(tile) && base.RuleMatch(neighbor, tile),
_ => (DefaultIncludesSibling && Siblings.Contains(tile)) || base.RuleMatch(neighbor, tile)
};
Crear un SiblingTile
- Haz clic derecho en la ventana Project y selecciona 2D > Tiles > SiblingTile.
- Configura las reglas de mosaico en el Inspector exactamente como en un RuleTile estándar.
- En la lista Siblings, arrastra los assets de tile con los que este tile debe conectarse.
- Activa DefaultIncludesSibling si la flecha verde por defecto (vecino = "This") también debe coincidir con los tiles hermanos. Es la configuración más común para fundir terrenos.
- Usa la constante de vecino Sibling en las reglas de mosaico cuando necesites reglas que se activen específicamente por adyacencia de hermanos.
Interfaces de comportamiento de tile
ICharacterInteractingTile
Los tiles que necesitan interacción en tiempo de ejecución con los personajes implementan ICharacterInteractingTile. MCECharacterController llama a estos ganchos durante el movimiento:
public interface ICharacterInteractingTile
{
bool HasBlockingInteraction();
// Async (coroutine) hooks -- called during movement animation
IEnumerator CharacterAboutToEnterTileAsync(MCECharacterController controller);
IEnumerator CharacterEnterTileAsync(MCECharacterController controller);
IEnumerator CharacterAboutToLeaveTileAsync(MCECharacterController controller);
IEnumerator CharacterLeftTileAsync(MCECharacterController controller);
// Callback hooks -- can cancel movement or suppress wild encounters
IEnumerator CharacterAboutToEnterTile(MCECharacterController controller, Action<bool, bool> finished);
IEnumerator CharacterEnterTile(MCECharacterController controller, Action<bool> finished);
IEnumerator CharacterAboutToLeaveTile(MCECharacterController controller, Action<bool> finished);
IEnumerator CharacterLeftTile(MCECharacterController controller, Action<bool> finished);
}
Las variantes con callback reciben un Action<bool> (o Action<bool, bool>) que permite al tile controlar si el personaje puede seguir moviéndose y si deben dispararse encuentros salvajes.
ITileTypeOverride
Implementa esta interfaz para sobrescribir el TileType en tiempo de ejecución según el contexto (posición, orden de ordenación, estado del juego):
public interface ITileTypeOverride
{
TileType GetOverride(GridController gridController,
Tilemap tilemap,
TileBase tile,
Vector3Int tilePosition,
int sortOrder);
}
La implementación más simple es TileTypeOverride, que devuelve un tipo fijo:
public class TileTypeOverride : OpenMonBehaviour<TileTypeOverride>, ITileTypeOverride
{
[SerializeField]
private TileType Override;
public TileType GetOverride(...) => Override;
}
Comportamientos de tile integrados
MCE trae varios comportamientos de tile que puedes usar como implementaciones de referencia:
| Clase | Propósito |
|---|---|
TallGrass | Ajusta el orden de ordenación del sprite cuando un personaje camina por ella; reproduce VFX al entrar; alterna la sombra del personaje |
ForceCharacterToKeepMoving | Fuerza el movimiento continuo en una dirección (cintas transportadoras, corrientes). Tiene HasBlockingInteraction() => true |
OneWayJumpableTile | Restringe el salto de una cornisa a una sola dirección |
BlockMovementDirections | Bloquea el movimiento en direcciones concretas desde un tile |
LadderUp | Ajusta el orden de ordenación del sprite para el recorrido vertical de una escalera |
EncounterTile | Marca un tile como zona de encuentros salvajes con un EncounterType concreto |
TileTypeOverride | Sobrescribe el TileType en tiempo de ejecución |
TileTypeOfTileBelow | Hereda el tipo del tile situado justo debajo en el orden de ordenación |
WaterfallEdge | Gestiona el comportamiento del borde de una cascada |
WhirlwindInDirection | Empuja al personaje en la dirección de un viento |
Crear un comportamiento de tile personalizado
Aquí tienes un ejemplo paso a paso para crear un tile de "Arenas movedizas" que retiene al jugador un momento cuando entra y suprime los encuentros salvajes:
Paso 1: Crear el MonoBehaviour
using System;
using System.Collections;
using UnityEngine;
using OpenMon.Foundation.Behaviours;
using MCECharacterController = OpenMon.MCE.Characters.MCECharacterController;
namespace OpenMon.MCE.World.Tiles
{
public class QuicksandTile : OpenMonBehaviour<QuicksandTile>, ICharacterInteractingTile
{
// The hook below waits, so the tile has to say it has a blocking interaction:
// the character controller only calls the callback hooks of such tiles.
public bool HasBlockingInteraction() => true;
// The character has just stepped in: hold it for half a second, then tell the
// controller not to trigger wild encounters on this tile (false = no encounter).
public IEnumerator CharacterEnterTile(MCECharacterController controller, Action<bool> finished)
{
yield return new WaitForSeconds(0.5f);
finished.Invoke(false);
}
// Remaining hooks -- no-op
public IEnumerator CharacterAboutToEnterTileAsync(MCECharacterController c) { yield break; }
public IEnumerator CharacterEnterTileAsync(MCECharacterController c) { yield break; }
public IEnumerator CharacterAboutToLeaveTileAsync(MCECharacterController c) { yield break; }
public IEnumerator CharacterLeftTileAsync(MCECharacterController c) { yield break; }
public IEnumerator CharacterAboutToEnterTile(MCECharacterController c, Action<bool, bool> f) { yield break; }
public IEnumerator CharacterAboutToLeaveTile(MCECharacterController c, Action<bool> f) { yield break; }
public IEnumerator CharacterLeftTile(MCECharacterController c, Action<bool> f) { yield break; }
}
}
Paso 2: Adjuntarlo a un prefab de tile
- Crea o edita el asset de tile que será arenas movedizas.
- Asegúrate de que esté habilitada la instanciación del Game Object del tile (RuleTile > Default Game Object o por regla).
- Adjunta tu componente
QuicksandTilea ese prefab.
Paso 3: Registrarlo en TileData
- Abre el asset
TileDataen el Inspector. - Usa el botón Populate para detectar los nuevos assets de tile.
- Establece el
TileTypedel tile enWalkable(o agrega un valor de enum personalizado si necesitas una lógica de movimiento especial). - Asigna el
BattleScenarioadecuado para el tema visual.
Paso 4: Pintarlo en el Tilemap
Usa la Tile Palette estándar de Unity para pintar tu tile en la capa de tilemap adecuada. El GridController recogerá automáticamente los datos del tile y llamará a los ganchos de tu comportamiento durante el juego.