/// <summary> /// Checks if the given sprite is valid for the given mask of positions. /// </summary> /// <param name="spriteNeighbourMask">The sprite to check against the mask of positions.</param> /// <param name="mask">The mask of tile positions to compare against.</param> /// <returns></returns> protected bool MatchesMask(SpriteNeighbourMask spriteNeighbourMask, SpriteNeighbour mask) { // Convert optional positions to 1 in both masks so they don't effect the comparison SpriteNeighbour tempMask = mask | spriteNeighbourMask.optionalNeighboursMask; SpriteNeighbour tempReq = spriteNeighbourMask.requiredNeighboursMask | spriteNeighbourMask.optionalNeighboursMask; return(tempMask == tempReq && spriteNeighbourMask.sprite); }
protected override Sprite GetSprite(SpriteNeighbour mask) { foreach (SpriteNeighbourMask sm in m_Sprites) { if (MatchesMask(sm, mask)) { return(sm.sprite); } } return(m_Error); }
protected override Sprite GetSprite(SpriteNeighbour mask) { foreach (AnimatedSpriteNeighbourMask sm in m_Sprites) { if (MatchesMask(sm, mask)) { m_CurrentSprite = sm; return(sm.sprite); } } return(m_Error); }
public override void GetTileData(Vector3Int position, ITilemap tilemap, ref TileData tileData) { base.GetTileData(position, tilemap, ref tileData); SpriteNeighbour mask = 0; for (int i = 0; i < m_PositionsToCheck.Length; i++) { mask += (byte)(HasTile(tilemap, position + m_PositionsToCheck[i]) ? Mathf.Pow(2, i) : 0); } tileData.sprite = GetSprite(mask); }
/// <summary> /// Generates a toggle grid for a sprite neighbour mask. /// </summary> /// <param name="offset">The position of the top-left corner of the grid</param> /// <param name="mask">The mask to generate a grid for</param> /// <returns>The mask value after being modified by user input</returns> protected SpriteNeighbour ToggleGrid(Rect rect, SpriteNeighbour mask, string label = "") { if (label != "") { Rect labelRect = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight); EditorGUI.LabelField(labelRect, label); // Shrink rect by area taken up by label so toggles are evenly distributed rect.y += EditorGUIUtility.singleLineHeight; rect.height -= EditorGUIUtility.singleLineHeight; } //EditorGUI.DrawRect(rect, new Color(1f, 0f, 0f)); // Subtract space taken by final row/col of toggles so they can be placed at xMax/yMax rect.width -= EditorGUIUtility.singleLineHeight; rect.height -= EditorGUIUtility.singleLineHeight; for (int r = 0; r < 3; r++) { for (int c = 0; c < 3; c++) { if (r != 1 || c != 1) { // Conditional reduces the array index once it skips the middle square, because there are only 8 enums but the loop counts 0 to 8 (9 positions) SpriteNeighbour positionMask = m_EnumValues[r * 3 + c - (r * 3 + c > 4 ? 1 : 0)]; bool value = (mask & positionMask) == positionMask; Rect checkboxRect = new Rect( Mathf.Lerp(rect.xMin, rect.xMax, c / 2f), Mathf.Lerp(rect.yMin, rect.yMax, r / 2f), EditorGUIUtility.singleLineHeight, // For some reason the checkbox is unclickable unless the width is doubled EditorGUIUtility.singleLineHeight ); value = EditorGUI.Toggle(checkboxRect, value); if (EditorGUI.Toggle(checkboxRect, value)) { // Toggle set to true, so set this bit to 1 with an OR mask mask = mask | positionMask; } else { // Toggle set to false, so set this bit to 0 with an inverted AND mask mask = mask & ~positionMask; } } } } return(mask); }
/// <summary> /// Render the control to the inspector. /// </summary> /// <param name="position">The rect containing the control.</param> /// <param name="property">The serialized property to render the control for.</param> /// <param name="label">The label for this property.</param> protected virtual void Render(Rect position, SerializedProperty property, GUIContent label) { SerializedProperty spriteProp = property.FindPropertyRelative("sprite"); SerializedProperty requiredMaskProp = property.FindPropertyRelative("requiredNeighboursMask"); SerializedProperty optionalMaskProp = property.FindPropertyRelative("optionalNeighboursMask"); // Place sprite field along the top above sprite preview and to the right of mask grids Rect spriteFieldRect = new Rect( position.x, position.y, position.width - maskGridSize * 2 - EditorGUIUtility.singleLineHeight * 2, EditorGUIUtility.singleLineHeight ); // Place sprite preview along left edge Rect spritePreviewRect = new Rect( position.x, position.y + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing, maskGridSize, maskGridSize ); // Place required mask grid second from the right (singleLineHeight away from optional mask grid) Rect requiredMaskFieldRect = new Rect( position.xMax - maskGridSize * 2 - EditorGUIUtility.singleLineHeight, position.y, maskGridSize, maskGridSize + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing ); // Place optional mask grid along right edge Rect optionalMaskFieldRect = new Rect( position.xMax - maskGridSize, position.y, maskGridSize, maskGridSize + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing ); SpriteNeighbour requiredMaskVal = (SpriteNeighbour)requiredMaskProp.intValue; SpriteNeighbour optionalMaskVal = (SpriteNeighbour)optionalMaskProp.intValue; bool val = EditorGUI.PropertyField(spriteFieldRect, spriteProp, GUIContent.none); // Render preview sprite Sprite sprite = spriteProp.objectReferenceValue as Sprite; if (sprite != null) { Rect spritesheetRect = new Rect( sprite.textureRect.x / sprite.texture.width, sprite.textureRect.y / sprite.texture.height, sprite.textureRect.width / sprite.texture.width, sprite.textureRect.height / sprite.texture.height ); GUI.DrawTextureWithTexCoords(spritePreviewRect, sprite.texture, spritesheetRect); } else { EditorGUI.DrawRect(spritePreviewRect, Color.grey); } requiredMaskVal = ToggleGrid(requiredMaskFieldRect, requiredMaskVal, "Required"); optionalMaskVal = ToggleGrid(optionalMaskFieldRect, optionalMaskVal, "Optional"); requiredMaskProp.intValue = (int)requiredMaskVal; optionalMaskProp.intValue = (int)optionalMaskVal; }
/// <summary> /// Gets the sprite matching the given mask of tile positions. /// </summary> /// <param name="mask">A mask of neighbouring tile positions.</param> /// <returns></returns> protected abstract Sprite GetSprite(SpriteNeighbour mask);