Initial Commit
This commit is contained in:
commit
ee5c2f922d
2255 changed files with 547750 additions and 0 deletions
293
Assets/Scripts/UI/ArHudManager.cs
Normal file
293
Assets/Scripts/UI/ArHudManager.cs
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
using Assets.Scripts.UI;
|
||||
using DefaultNamespace;
|
||||
using DefaultNamespace.Util;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using TMPro;
|
||||
using Trive.Mono.Utils;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.UI;
|
||||
using Zenject;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace UI
|
||||
{
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateBefore(typeof(PlayerCoverSystemWeaponAdjust))]
|
||||
public class ArHudManager : InjectableComponentSystem, IInitializable
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public TMP_Text Ammo;
|
||||
public VerticalLayoutGroup AmmoGroup;
|
||||
public GameObject AmmoObj;
|
||||
public Canvas Canvas;
|
||||
public TMP_Text ClipAmmo;
|
||||
public Gradient ClipAmmoColor;
|
||||
public GameObject ClipAmmoObj;
|
||||
public LineRenderer CoverLine;
|
||||
[Range(0, 1)] public float CoverLineAlpha = 0.2f;
|
||||
public TMP_Text Grenades;
|
||||
public GameObject GrenadesObj;
|
||||
public Gradient HealthGradient;
|
||||
public TMP_Text HealthPackCount;
|
||||
public Slider HealthSlider;
|
||||
public RectTransform HeathGroup;
|
||||
public Slider MaxRegenSlider;
|
||||
public HorizontalLayoutGroup SliderGroup;
|
||||
public int SlotCount;
|
||||
public GameObject SlotPrefab;
|
||||
public RectTransform StatusBar;
|
||||
public Vector2 StatusBarOffset;
|
||||
public RectTransform TakeBar;
|
||||
public Vector2 TakeBarOffset;
|
||||
public RectTransform VaultIndicator;
|
||||
public float ZeroesAlpha;
|
||||
}
|
||||
|
||||
[Inject] private readonly Camera camera;
|
||||
[Inject] private readonly PlayerCoverSystem.Settings coverSystemSettings;
|
||||
[Inject(Id = AssetManifest.HealthKit)] private readonly AssetReferenceT<ItemPrefab> healthKit;
|
||||
|
||||
[Inject] private readonly ItemPickupSystem.Settings pickupSystemSettings;
|
||||
[Inject] private readonly Settings settings;
|
||||
[Inject] private readonly PlayerVitalsSystem.Settings vitalsSystemSettings;
|
||||
private List<Entity> CloseItems;
|
||||
private readonly List<SlotPartsData> slotEntries = new List<SlotPartsData>();
|
||||
|
||||
[Inject] private PlayerVitalsSystem vitalsSystem;
|
||||
private Regex zeroesRegex;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
zeroesRegex = new Regex("^0+", RegexOptions.Compiled);
|
||||
slotEntries.Add(
|
||||
new SlotPartsData
|
||||
{
|
||||
Amount = settings.SlotPrefab.FindChild<TextMeshProUGUI>("$Amount"),
|
||||
Highlight = settings.SlotPrefab.FindChild<Graphic>("$Highlight"),
|
||||
Icon = settings.SlotPrefab.FindChild<SpriteImage>("$Icon")
|
||||
});
|
||||
for (var i = 0; i < settings.SlotCount - 1; i++)
|
||||
{
|
||||
var slotInstance = Object.Instantiate(settings.SlotPrefab, settings.SlotPrefab.transform.parent);
|
||||
slotEntries.Add(
|
||||
new SlotPartsData
|
||||
{
|
||||
Amount = slotInstance.FindChild<TextMeshProUGUI>("$Amount"),
|
||||
Highlight = slotInstance.FindChild<Graphic>("$Highlight"),
|
||||
Icon = slotInstance.FindChild<SpriteImage>("$Icon")
|
||||
});
|
||||
}
|
||||
|
||||
foreach (var slotEntry in slotEntries)
|
||||
{
|
||||
slotEntry.Amount.text = "";
|
||||
slotEntry.Highlight.enabled = false;
|
||||
slotEntry.Icon.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnCreate()
|
||||
{
|
||||
CloseItems = new List<Entity>();
|
||||
}
|
||||
|
||||
protected override void OnStartRunning()
|
||||
{
|
||||
settings.Canvas.enabled = true;
|
||||
}
|
||||
|
||||
protected override void OnStopRunning()
|
||||
{
|
||||
if (settings.Canvas != null)
|
||||
{
|
||||
settings.Canvas.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.WithAllReadOnly<Slot, PlayerFacade, ActorBodyParts>()
|
||||
.ForEach(
|
||||
(
|
||||
Entity entity,
|
||||
ref PlayerData player,
|
||||
ref ActorData actor,
|
||||
ref Rotation2D rotation,
|
||||
ref LocalPlayerData localPlayerData,
|
||||
ref RigidBody2DData rigidBody) =>
|
||||
{
|
||||
var parts = EntityManager.GetComponentObject<ActorBodyParts>(entity);
|
||||
var facade = EntityManager.GetComponentObject<PlayerFacade>(entity);
|
||||
var inventory = EntityManager.GetBuffer<Slot>(entity);
|
||||
|
||||
var healthPacks = inventory.Begin().Where(d => d.Type == SlotType.Health && d.HasItem()).Sum(d => d.Item.Amount);
|
||||
var hasGrenadeSlot = inventory.Begin().Any(d => d.Type == SlotType.Grenade);
|
||||
var grenades = inventory.Begin().FirstOrDefault(s => s.Type == SlotType.Grenade && s.HasItem()).Item.Amount;
|
||||
var healthPercent = Mathf.Clamp01(actor.Health / facade.MaxHealth);
|
||||
var healthColor = settings.HealthGradient.Evaluate(healthPercent);
|
||||
settings.HealthSlider.value = healthPercent;
|
||||
settings.MaxRegenSlider.value = Mathf.Clamp01(vitalsSystemSettings.MaxRegenHealth / facade.MaxHealth);
|
||||
settings.HealthSlider.colors = new ColorBlock { normalColor = healthColor, colorMultiplier = 1 };
|
||||
settings.GrenadesObj.gameObject.SetActive(hasGrenadeSlot);
|
||||
SetAmountText(settings.Grenades, grenades, "00");
|
||||
|
||||
var hasWeapon = EntityManager.HasComponent<ActorWeaponReferenceData>(entity);
|
||||
settings.AmmoObj.SetActive(hasWeapon);
|
||||
settings.ClipAmmoObj.SetActive(hasWeapon);
|
||||
|
||||
if (hasWeapon)
|
||||
{
|
||||
var weaponReference = EntityManager.GetComponentData<ActorWeaponReferenceData>(entity);
|
||||
if (EntityManager.Exists(weaponReference.Weapon) &&
|
||||
EntityManager.TryGetComponentData<WeaponData>(weaponReference.Weapon, out var weaponData) &&
|
||||
EntityManager.TryGetSharedComponentData<WeaponPropertiesData>(weaponReference.Weapon, out var weapon))
|
||||
{
|
||||
SetAmountText(settings.ClipAmmo, weaponData.ClipAmmo, "00");
|
||||
settings.ClipAmmo.color =
|
||||
settings.ClipAmmoColor.Evaluate((float)weaponData.ClipAmmo / weapon.Weapon.Data.ClipCapacity);
|
||||
SetAmountText(settings.Ammo, weaponData.Ammo, "000");
|
||||
}
|
||||
}
|
||||
|
||||
var leftSide = Mathf.Sign(facade.transform.right.x) > 0;
|
||||
settings.SliderGroup.childAlignment = leftSide ? TextAnchor.LowerLeft : TextAnchor.LowerRight;
|
||||
settings.HeathGroup.SetSiblingIndex(leftSide ? 0 : 1);
|
||||
settings.AmmoGroup.childAlignment = leftSide ? TextAnchor.LowerLeft : TextAnchor.LowerRight;
|
||||
var screenCenter = RectTransformUtility.WorldToScreenPoint(camera, parts.Hip.position);
|
||||
settings.StatusBar.anchoredPosition = screenCenter +
|
||||
Vector2.left *
|
||||
rotation.Axis *
|
||||
(leftSide ? settings.StatusBarOffset.x : settings.StatusBarOffset.y);
|
||||
settings.TakeBar.anchoredPosition =
|
||||
screenCenter + Vector2.left * (leftSide ? settings.TakeBarOffset.x : settings.TakeBarOffset.y);
|
||||
SetAmountText(settings.HealthPackCount, healthPacks, "0");
|
||||
|
||||
ManageTakeBar(facade, ref player);
|
||||
ManageCoverUi(entity, rigidBody, actor, rotation, parts, facade);
|
||||
});
|
||||
}
|
||||
|
||||
private void ManageCoverUi(
|
||||
Entity entity,
|
||||
RigidBody2DData rigidBody,
|
||||
ActorData actor,
|
||||
Rotation2D rotation,
|
||||
ActorBodyParts parts,
|
||||
PlayerFacade facade)
|
||||
{
|
||||
if (EntityManager.TryGetComponentData<ActorCoverRaycastData>(entity, out var raycast))
|
||||
{
|
||||
float heightOffset;
|
||||
|
||||
if (EntityManager.TryGetComponentData<PlayerCoverData>(entity, out var coverData))
|
||||
{
|
||||
heightOffset = coverData.WeaponOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
heightOffset = raycast.TopHit.y + coverSystemSettings.Offset - parts.WeaponContainer.transform.position.y;
|
||||
}
|
||||
|
||||
var hasCover = EntityManager.HasComponent<PlayerCoverData>(entity) &&
|
||||
raycast.HadForwardHit &&
|
||||
heightOffset > 0 &&
|
||||
actor.Grounded &&
|
||||
Vector2.Angle(raycast.TopNormal, Vector2.up) <= 22.5f &&
|
||||
Vector2.Angle(raycast.ForwardNormal, Vector2.right * rotation.Axis) <= 22.5f;
|
||||
var canVault = EntityManager.HasComponent<PlayerVaultData>(entity);
|
||||
settings.CoverLine.positionCount = hasCover ? 4 : 0;
|
||||
settings.VaultIndicator.gameObject.SetActive(canVault);
|
||||
|
||||
var topRight = new Vector3(raycast.ForwardHit.x, raycast.TopHit.y);
|
||||
Vector3 topLeft = raycast.TopHit;
|
||||
var bottomRight = new Vector3(raycast.ForwardHit.x, raycast.TopHit.y - raycast.Height);
|
||||
var playerFeet = new Vector3(rigidBody.Position.x, raycast.TopHit.y - raycast.Height);
|
||||
|
||||
if (hasCover)
|
||||
{
|
||||
var healthPercent = Mathf.Clamp01(actor.Health / facade.MaxHealth);
|
||||
var col = settings.HealthGradient.Evaluate(healthPercent);
|
||||
settings.CoverLine.startColor = col * new Color(1, 1, 1, settings.CoverLineAlpha);
|
||||
settings.CoverLine.endColor = col * new Color(1, 1, 1, 0);
|
||||
settings.CoverLine.SetPositions(new[] { topLeft, topRight, bottomRight, playerFeet });
|
||||
}
|
||||
|
||||
if (canVault)
|
||||
{
|
||||
var vaultData = EntityManager.GetComponentData<PlayerVaultData>(entity);
|
||||
var parent = settings.VaultIndicator.transform.parent as RectTransform;
|
||||
var sizeDelta = settings.VaultIndicator.sizeDelta;
|
||||
var indicatorScreenPos = RectTransformUtility.WorldToScreenPoint(camera, vaultData.VaultPoint);
|
||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(parent, indicatorScreenPos, camera, out var indicatorPos);
|
||||
settings.VaultIndicator.anchoredPosition = indicatorPos +
|
||||
Vector2.down * (8 + sizeDelta.y * 0.5f) +
|
||||
Vector2.left * rotation.Axis * (8 + sizeDelta.x * 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetAmountText(TMP_Text text, int amount, string format)
|
||||
{
|
||||
var str = amount.ToString(format);
|
||||
if (text.name != str)
|
||||
{
|
||||
text.text = zeroesRegex.Replace(str, m => $"<alpha=#{Mathf.RoundToInt(settings.ZeroesAlpha * 255):X}>{m.Value}<alpha=#FF>");
|
||||
text.name = str;
|
||||
}
|
||||
}
|
||||
|
||||
private void ManageTakeBar(PlayerFacade facade, ref PlayerData player)
|
||||
{
|
||||
var pickupDistanceSqr = pickupSystemSettings.PickupDistance * pickupSystemSettings.PickupDistance;
|
||||
|
||||
CloseItems.Clear();
|
||||
|
||||
Entities.ForEach(
|
||||
(Entity entity, SpriteRenderer renderer, ref ItemContainerData container) =>
|
||||
{
|
||||
var d = Vector2.SqrMagnitude(renderer.transform.position - facade.transform.position);
|
||||
if (d <= pickupDistanceSqr)
|
||||
{
|
||||
CloseItems.Add(entity);
|
||||
}
|
||||
});
|
||||
|
||||
for (var i = 0; i < CloseItems.Count; i++)
|
||||
{
|
||||
if (i < slotEntries.Count)
|
||||
{
|
||||
var itemEntity = CloseItems[i];
|
||||
slotEntries[i].Icon.sprite = EntityManager.GetComponentObject<SpriteRenderer>(CloseItems[i]).sprite;
|
||||
slotEntries[i].Icon.enabled = true;
|
||||
if (EntityManager.TryGetComponentData<ItemContainerAmountData>(itemEntity, out var itemAmount))
|
||||
{
|
||||
slotEntries[i].Amount.enabled = true;
|
||||
slotEntries[i].Amount.text = itemAmount.Amount.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
slotEntries[i].Amount.enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < slotEntries.Count; i++)
|
||||
{
|
||||
slotEntries[i].Highlight.enabled = player.PickupIndex == i;
|
||||
if (i >= CloseItems.Count)
|
||||
{
|
||||
slotEntries[i].Icon.sprite = null;
|
||||
slotEntries[i].Amount.enabled = false;
|
||||
slotEntries[i].Icon.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
settings.TakeBar.gameObject.SetActive(CloseItems.Count > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/UI/ArHudManager.cs.meta
Normal file
3
Assets/Scripts/UI/ArHudManager.cs.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1f55fe477f3f4ba4b31e1217a2d3b095
|
||||
timeCreated: 1531595273
|
||||
101
Assets/Scripts/UI/CursorManager.cs
Normal file
101
Assets/Scripts/UI/CursorManager.cs
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
using DefaultNamespace;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
using Zenject;
|
||||
|
||||
namespace UI
|
||||
{
|
||||
public class CursorManager : InjectableComponentSystem, IInitializable
|
||||
{
|
||||
public enum CursorType { Aim, Ui }
|
||||
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public CursorGraphic AimingCursorGraphic;
|
||||
public Image ClipAmmo;
|
||||
public Color InvalidCursorColor;
|
||||
public float MinWeaponCursorDistance;
|
||||
public CursorGraphic UiCursorGraphic;
|
||||
public Color ValidCursorColor;
|
||||
public Graphic WeaponCrosshair;
|
||||
}
|
||||
|
||||
[Inject] private readonly Camera camera;
|
||||
[Inject] private readonly EventSystem eventSystem;
|
||||
[Inject] private readonly PlayerLookSystem lookSystem;
|
||||
[Inject] private readonly Settings settings;
|
||||
private CursorType currentCursorType;
|
||||
|
||||
[Inject] private PlayerWeaponSystem weaponSystem;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
settings.WeaponCrosshair.rectTransform.anchorMin = settings.WeaponCrosshair.rectTransform.anchorMax = Vector2.zero;
|
||||
Cursor.lockState = CursorLockMode.Confined;
|
||||
currentCursorType = CursorType.Ui;
|
||||
Cursor.SetCursor(settings.UiCursorGraphic.Texture, settings.UiCursorGraphic.Center, CursorMode.Auto);
|
||||
settings.WeaponCrosshair.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
protected override void OnStopRunning()
|
||||
{
|
||||
if (settings.WeaponCrosshair != null)
|
||||
{
|
||||
settings.WeaponCrosshair.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(ActorWeaponPropertiesData weapon, ref PlayerData player, ref ActorData actor, ref ActorWeaponReferenceData weaponReference) =>
|
||||
{
|
||||
var weaponData = GetComponentDataFromEntity<WeaponData>(true)[weaponReference.Weapon];
|
||||
var weaponEntity = weaponReference.Weapon;
|
||||
if (EntityManager.Exists(weaponEntity))
|
||||
{
|
||||
var weaponParts = EntityManager.GetSharedComponentData<WeaponPartsData>(weaponEntity);
|
||||
settings.WeaponCrosshair.gameObject.SetActive(weaponParts.Barrel != null);
|
||||
if (weaponParts.Barrel != null)
|
||||
{
|
||||
var canAim = weaponSystem.CanFire(weaponParts.Barrel.position);
|
||||
settings.WeaponCrosshair.color = canAim ? settings.ValidCursorColor : settings.InvalidCursorColor;
|
||||
var distance = canAim
|
||||
? lookSystem.CanAim(actor.Aim) ? Mathf.Max(
|
||||
Vector2.Distance(actor.Aim, weaponParts.Barrel.position),
|
||||
settings.MinWeaponCursorDistance) : settings.MinWeaponCursorDistance
|
||||
: 0;
|
||||
settings.WeaponCrosshair.rectTransform.anchoredPosition =
|
||||
camera.WorldToScreenPoint(weaponParts.Barrel.position + weaponParts.Barrel.right * distance);
|
||||
}
|
||||
}
|
||||
|
||||
settings.ClipAmmo.fillAmount = (float)weaponData.ClipAmmo / weapon.Weapon.Data.ClipCapacity;
|
||||
var cursor = eventSystem.IsPointerOverGameObject() ? CursorType.Ui : CursorType.Aim;
|
||||
if (currentCursorType != cursor)
|
||||
{
|
||||
currentCursorType = cursor;
|
||||
var cursorGraphic = settings.UiCursorGraphic;
|
||||
switch (cursor)
|
||||
{
|
||||
case CursorType.Aim:
|
||||
cursorGraphic = settings.AimingCursorGraphic;
|
||||
break;
|
||||
}
|
||||
|
||||
Cursor.SetCursor(cursorGraphic.Texture, cursorGraphic.Center, CursorMode.Auto);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct CursorGraphic
|
||||
{
|
||||
public Texture2D Texture;
|
||||
public Vector2 Center;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/UI/CursorManager.cs.meta
Normal file
3
Assets/Scripts/UI/CursorManager.cs.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 49fa529521b34eedb3ca952a3fa15d3b
|
||||
timeCreated: 1530991600
|
||||
42
Assets/Scripts/UI/HudManager.cs
Normal file
42
Assets/Scripts/UI/HudManager.cs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
using DefaultNamespace;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace UI
|
||||
{
|
||||
public class HudManager : InjectableComponentSystem
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public CanvasGroup BloodyScreen;
|
||||
public float CriticalHealth;
|
||||
public GameObject GameOverScreen;
|
||||
}
|
||||
|
||||
[Inject] private readonly Settings settings;
|
||||
|
||||
protected override void OnStartRunning()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnStopRunning()
|
||||
{
|
||||
if (settings.BloodyScreen != null)
|
||||
{
|
||||
settings.BloodyScreen.alpha = 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(ref PlayerData player, ref ActorData actor) =>
|
||||
{
|
||||
settings.BloodyScreen.alpha = 1 - Mathf.Clamp01(actor.Health / settings.CriticalHealth);
|
||||
settings.GameOverScreen.SetActive(actor.Health <= 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/UI/HudManager.cs.meta
Normal file
3
Assets/Scripts/UI/HudManager.cs.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bccd3fcaa8fd47d7a8692efeb399b768
|
||||
timeCreated: 1531417637
|
||||
303
Assets/Scripts/UI/InventoryUiSystem.cs
Normal file
303
Assets/Scripts/UI/InventoryUiSystem.cs
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
using DefaultNamespace;
|
||||
using Events;
|
||||
using Markers;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Trive.Mono.Utils;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.EventSystems;
|
||||
using Zenject;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace UI
|
||||
{
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateBefore(typeof(InventorySystem))]
|
||||
public class InventoryUiSystem : InjectableComponentSystem
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public Canvas Canvas;
|
||||
public float DistanceFromPlayer;
|
||||
public Sprite GrenadeSlotIcon;
|
||||
public Sprite HealthSlotIcon;
|
||||
public Sprite MeleeSlotIcon;
|
||||
public GameObject SlotPrefab;
|
||||
public Transform SlotsContainer;
|
||||
public GameObject SpecialSlotPrefab;
|
||||
public Sprite WeaponSlotIcon;
|
||||
}
|
||||
|
||||
[Inject] private Camera camera;
|
||||
|
||||
[Inject] private Settings settings;
|
||||
|
||||
protected override void OnStartRunning()
|
||||
{
|
||||
settings.Canvas.enabled = true;
|
||||
}
|
||||
|
||||
protected override void OnStopRunning()
|
||||
{
|
||||
if (settings.Canvas != null)
|
||||
{
|
||||
settings.Canvas.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
ManageInitialization();
|
||||
ManageWindowOpening();
|
||||
ManageWindowClosing();
|
||||
|
||||
Entities.WithAllReadOnly<RectTransform, SlotReference>()
|
||||
.ForEach(
|
||||
(
|
||||
Entity windowEntity,
|
||||
InventoryWindowData inventoryWindow,
|
||||
ref WindowComponentData windowComponent,
|
||||
ref EnabledComponentData enabled) =>
|
||||
{
|
||||
var inventoryEntity = inventoryWindow.Inventory;
|
||||
if (EntityManager.Exists(inventoryEntity))
|
||||
{
|
||||
var windowTransform = EntityManager.GetComponentObject<RectTransform>(windowEntity);
|
||||
var slots = EntityManager.GetBuffer<SlotReference>(windowEntity);
|
||||
|
||||
var inventoryEntityParts = EntityManager.GetComponentObject<ActorBodyParts>(inventoryEntity);
|
||||
var inventoryEntityRot = EntityManager.GetComponentData<Rotation2D>(inventoryEntity);
|
||||
var inventoryEntityActorData = EntityManager.GetComponentData<ActorData>(inventoryEntity);
|
||||
|
||||
var screenPlayerPos = RectTransformUtility.WorldToScreenPoint(camera, inventoryEntityParts.Head.position);
|
||||
var screenForwardPoint = RectTransformUtility.WorldToScreenPoint(
|
||||
camera,
|
||||
inventoryEntityParts.Head.position + Vector3.left * inventoryEntityRot.Axis);
|
||||
var screenLookDir = (screenForwardPoint - screenPlayerPos).normalized;
|
||||
var screenEndPoint = screenPlayerPos + screenLookDir * settings.DistanceFromPlayer;
|
||||
Vector2 worldEndPoint = camera.ScreenToWorldPoint(screenEndPoint);
|
||||
if (windowTransform.anchoredPosition != screenEndPoint)
|
||||
{
|
||||
windowTransform.anchoredPosition = screenEndPoint;
|
||||
}
|
||||
inventoryEntityActorData.Aim = worldEndPoint;
|
||||
|
||||
if (EntityManager.HasComponent<InventoryDirtyEventData>(inventoryEntity))
|
||||
{
|
||||
var inventory = EntityManager.GetBuffer<Slot>(inventoryEntity);
|
||||
|
||||
for (var j = 0; j < slots.Length; j++)
|
||||
{
|
||||
UpdateSlot(
|
||||
EntityManager.GetSharedComponentData<SlotPartsData>(slots[j].Slot),
|
||||
inventory[j].Item,
|
||||
EntityManager.GetComponentData<SlotUiData>(slots[j].Slot),
|
||||
slots[j].Slot);
|
||||
}
|
||||
}
|
||||
|
||||
EntityManager.SetComponentData(inventoryEntity, inventoryEntityActorData);
|
||||
}
|
||||
else
|
||||
{
|
||||
//close the window
|
||||
PostUpdateCommands.RemoveComponent<EnabledComponentData>(windowEntity);
|
||||
PostUpdateCommands.AddComponent(windowEntity, new WindowCloseEventData());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void ManageWindowClosing()
|
||||
{
|
||||
Entities.ForEach(
|
||||
(Entity entity, InventoryWindowData window, ref WindowOpenEventData e) =>
|
||||
{
|
||||
if (EntityManager.HasComponent<OverEvent>(entity))
|
||||
{
|
||||
PostUpdateCommands.RemoveComponent<OverEvent>(entity);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void ManageWindowOpening()
|
||||
{
|
||||
Entities.WithAll<SlotReference>()
|
||||
.ForEach(
|
||||
(Entity windowEntity, InventoryWindowData window, ref WindowOpenEventData e) =>
|
||||
{
|
||||
var inventoryEntity = window.Inventory;
|
||||
var inventory = EntityManager.GetBuffer<Slot>(inventoryEntity);
|
||||
var slots = EntityManager.GetBuffer<SlotReference>(windowEntity);
|
||||
|
||||
for (var j = 0; j < slots.Length; j++)
|
||||
{
|
||||
var slotData = EntityManager.GetComponentData<SlotUiData>(slots[j].Slot);
|
||||
var slotParts = EntityManager.GetSharedComponentData<SlotPartsData>(slots[j].Slot);
|
||||
UpdateSlot(slotParts, inventory[j].Item, slotData, slots[j].Slot);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void ManageInitialization()
|
||||
{
|
||||
Entities.WithNone<InitializedComponentData>()
|
||||
.ForEach(
|
||||
(Entity windowEntity, InventoryWindowData window) =>
|
||||
{
|
||||
var inventoryEntity = window.Inventory;
|
||||
var inventory = EntityManager.GetBuffer<Slot>(inventoryEntity);
|
||||
var inventoryLength = inventory.Length;
|
||||
|
||||
PostUpdateCommands.AddComponent(windowEntity, new InitializedComponentData());
|
||||
PostUpdateActions.Enqueue(
|
||||
() =>
|
||||
{
|
||||
var buffer = EntityManager.AddBuffer<SlotReference>(windowEntity);
|
||||
buffer.Fill(inventoryLength);
|
||||
});
|
||||
|
||||
var windowTrigger = EntityManager.GetComponentObject<EventTrigger>(windowEntity);
|
||||
windowTrigger.triggers.First(e => e.eventID == EventTriggerType.PointerEnter)
|
||||
.callback.AddListener(e => { EntityManager.AddComponent(windowEntity, ComponentType.ReadWrite<OverEvent>()); });
|
||||
windowTrigger.triggers.First(e => e.eventID == EventTriggerType.PointerExit)
|
||||
.callback.AddListener(e => { EntityManager.RemoveComponent<OverEvent>(windowEntity); });
|
||||
|
||||
for (var j = 0; j < inventory.Length; j++)
|
||||
{
|
||||
var specialSlot = inventory[j].Type != SlotType.None;
|
||||
var slotObj = Object.Instantiate(specialSlot ? settings.SpecialSlotPrefab : settings.SlotPrefab, settings.SlotsContainer);
|
||||
var slotParts = slotObj.FindChildrenGroup<SlotPartsData>(includeHidden: true);
|
||||
switch (inventory[j].Type)
|
||||
{
|
||||
case SlotType.RangedWeapon:
|
||||
slotParts.SlotIcon.sprite = settings.WeaponSlotIcon;
|
||||
break;
|
||||
|
||||
case SlotType.MeleeWeapon:
|
||||
slotParts.SlotIcon.sprite = settings.MeleeSlotIcon;
|
||||
break;
|
||||
|
||||
case SlotType.Grenade:
|
||||
slotParts.SlotIcon.sprite = settings.GrenadeSlotIcon;
|
||||
break;
|
||||
|
||||
case SlotType.Health:
|
||||
slotParts.SlotIcon.sprite = settings.HealthSlotIcon;
|
||||
break;
|
||||
}
|
||||
|
||||
slotParts.SlotIcon.gameObject.SetActive(specialSlot);
|
||||
var slot = new SlotUiData { Index = j, Inventory = inventoryEntity, SpecialSlot = specialSlot };
|
||||
var slotIndex = j;
|
||||
slotParts.Trigger.triggers.First(e => e.eventID == EventTriggerType.BeginDrag)
|
||||
.callback.AddListener(
|
||||
e =>
|
||||
{
|
||||
var inv = EntityManager.GetBuffer<Slot>(inventoryEntity);
|
||||
if (inv[slotIndex].HasItem() && !EntityManager.HasComponent<ItemDragEvent>(inventoryEntity))
|
||||
{
|
||||
var s = inv[slotIndex];
|
||||
var item = s.Item;
|
||||
s.Item = new ItemData();
|
||||
inv[slotIndex] = s;
|
||||
EntityManager.AddSharedComponentData(
|
||||
inventoryEntity,
|
||||
new ItemDragEvent
|
||||
{
|
||||
Item = item, Slot = slotIndex, ScreenPos = camera.WorldToScreenPoint(slotObj.transform.position)
|
||||
});
|
||||
EntityManager.PostEntityEvent<InventoryDirtyEventData>(inventoryEntity);
|
||||
}
|
||||
});
|
||||
|
||||
PostUpdateActions.Enqueue(
|
||||
() =>
|
||||
{
|
||||
var entity = GameObjectEntity.AddToEntityManager(EntityManager, slotObj);
|
||||
EntityManager.AddSharedComponentData(entity, slotParts);
|
||||
EntityManager.AddComponentData(entity, slot);
|
||||
var array = EntityManager.GetBuffer<SlotReference>(windowEntity);
|
||||
array[slotIndex] = new SlotReference { Slot = entity };
|
||||
slotParts.Trigger.triggers.First(t => t.eventID == EventTriggerType.Select)
|
||||
.callback.AddListener(
|
||||
e =>
|
||||
{
|
||||
EntityManager.PostEntityEvent<SelectEvent>(entity);
|
||||
UpdateSlotSelected(EntityManager.GetSharedComponentData<SlotPartsData>(entity), entity);
|
||||
});
|
||||
slotParts.Trigger.triggers.First(t => t.eventID == EventTriggerType.Deselect)
|
||||
.callback.AddListener(
|
||||
e =>
|
||||
{
|
||||
EntityManager.RemoveComponent<SelectEvent>(entity);
|
||||
UpdateSlotSelected(EntityManager.GetSharedComponentData<SlotPartsData>(entity), entity);
|
||||
});
|
||||
slotParts.Trigger.triggers.First(e => e.eventID == EventTriggerType.PointerEnter)
|
||||
.callback.AddListener(e => { EntityManager.PostEntityEvent<OverEvent>(entity); });
|
||||
slotParts.Trigger.triggers.First(e => e.eventID == EventTriggerType.PointerExit)
|
||||
.callback.AddListener(e => { EntityManager.RemoveComponent<OverEvent>(entity); });
|
||||
slotParts.Trigger.triggers.First(e => e.eventID == EventTriggerType.PointerClick)
|
||||
.callback.AddListener(
|
||||
e =>
|
||||
{
|
||||
//EventSystem.current.SetSelectedGameObject(slotObj,e);
|
||||
if (((PointerEventData)e).clickCount > 1 &&
|
||||
!EntityManager.HasComponent<ItemUseEventData>(inventoryEntity))
|
||||
{
|
||||
EntityManager.AddComponentData(
|
||||
inventoryEntity,
|
||||
new ItemUseEventData { Inventory = inventoryEntity, Slot = slotIndex });
|
||||
}
|
||||
});
|
||||
var playerInventory = EntityManager.GetBuffer<Slot>(inventoryEntity);
|
||||
UpdateSlot(slotParts, playerInventory[slotIndex].Item, slot, entity);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void UpdateSlotSelected(SlotPartsData slotParts, Entity slotEntity)
|
||||
{
|
||||
slotParts.Highlight.enabled = EntityManager.HasComponent<SelectEvent>(slotEntity);
|
||||
}
|
||||
|
||||
private void UpdateSlot(SlotPartsData slotParts, ItemData item, SlotUiData slotUiData, Entity slotEntity)
|
||||
{
|
||||
UpdateSlotSelected(slotParts, slotEntity);
|
||||
slotParts.Amount.enabled = item.Item.IsValid && item.Amount > 1;
|
||||
slotParts.SlotIcon.enabled = !(item.Item.IsValid && item.Amount > 0) && slotUiData.SpecialSlot;
|
||||
slotParts.IconBackground.enabled = item.Amount > 0 && item.Item.IsValid;
|
||||
if (item.Amount > 1)
|
||||
{
|
||||
slotParts.Amount.text = item.Amount.ToString();
|
||||
}
|
||||
slotParts.Icon.enabled = item.Item.IsValid;
|
||||
if (item.Item.IsValid)
|
||||
{
|
||||
var assetOperation = Addressables.LoadAssetAsync<ItemPrefab>(item.Item.ToString());
|
||||
if (assetOperation.IsValid())
|
||||
{
|
||||
if (assetOperation.IsDone)
|
||||
{
|
||||
if (assetOperation.Result != null)
|
||||
{
|
||||
slotParts.Icon.sprite = assetOperation.Result.Icon;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assetOperation.Completed += operation =>
|
||||
{
|
||||
if (assetOperation.Result != null)
|
||||
{
|
||||
slotParts.Icon.sprite = operation.Result?.Icon;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/UI/InventoryUiSystem.cs.meta
Normal file
3
Assets/Scripts/UI/InventoryUiSystem.cs.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6830eba58b4e468f9c5135a5630ff7d1
|
||||
timeCreated: 1532181229
|
||||
9
Assets/Scripts/UI/InventoryWindowData.cs
Normal file
9
Assets/Scripts/UI/InventoryWindowData.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
using Unity.Entities;
|
||||
|
||||
namespace UI
|
||||
{
|
||||
public struct InventoryWindowData : ISharedComponentData
|
||||
{
|
||||
public Entity Inventory;
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/UI/InventoryWindowData.cs.meta
Normal file
3
Assets/Scripts/UI/InventoryWindowData.cs.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0e4c2fd629ef41c781a639b902342f0b
|
||||
timeCreated: 1532424231
|
||||
123
Assets/Scripts/UI/ItemDraggingSystem.cs
Normal file
123
Assets/Scripts/UI/ItemDraggingSystem.cs
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
using Assets.Scripts.UI;
|
||||
using DefaultNamespace;
|
||||
using Events;
|
||||
using System;
|
||||
using TMPro;
|
||||
using Tween;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using Zenject;
|
||||
|
||||
namespace UI
|
||||
{
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup))]
|
||||
public class ItemDraggingSystem : AdvancedComponentSystem, IInitializable
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public TMP_Text Amount;
|
||||
public Canvas ItemCanvas;
|
||||
public RectTransform ItemContainer;
|
||||
public GameObjectEntity ItemGroup;
|
||||
public SpriteImage ItemImage;
|
||||
}
|
||||
|
||||
[Inject] private readonly Camera camera;
|
||||
[Inject] private readonly Settings settings;
|
||||
|
||||
[Inject] private TweenSystem tweenSystem;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
settings.ItemCanvas.enabled = false;
|
||||
}
|
||||
|
||||
protected override void OnStartRunning()
|
||||
{
|
||||
settings.ItemCanvas.enabled = false;
|
||||
}
|
||||
|
||||
protected override void OnStopRunning()
|
||||
{
|
||||
if (settings.ItemCanvas != null)
|
||||
{
|
||||
settings.ItemCanvas.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
var enableItemCanvasFlag = false;
|
||||
|
||||
Entities.ForEach(
|
||||
(Entity entity, ItemDragEvent e, ref PlayerInput input) =>
|
||||
{
|
||||
enableItemCanvasFlag = true;
|
||||
|
||||
if (e.ItemPrefab.IsEmpty)
|
||||
{
|
||||
settings.Amount.text = e.Item.Amount.ToString();
|
||||
settings.Amount.enabled = e.Item.Amount > 1;
|
||||
e.ItemPrefab = new AsyncOperationWrapper<ItemPrefab>(Addressables.LoadAssetAsync<ItemPrefab>(e.Item.Item.ToString()));
|
||||
e.ItemPrefab.Completed += operation =>
|
||||
{
|
||||
if (operation.IsValid)
|
||||
{
|
||||
settings.ItemImage.sprite = operation.Result?.Icon;
|
||||
}
|
||||
};
|
||||
|
||||
settings.ItemContainer.anchoredPosition = Input.mousePosition;
|
||||
|
||||
//PostUpdateCommands.StartTween(settings.ItemGroup.Entity, 0.6f, EaseType.easeOutElastic, new TweenMoveToMouseData() { FromPosition = e.ScreenPos });
|
||||
PostUpdateCommands.SetSharedComponent(entity, e);
|
||||
}
|
||||
else if (!e.ItemPrefab.IsValid)
|
||||
{
|
||||
PostUpdateCommands.RemoveComponent<ItemDragEvent>(entity);
|
||||
tweenSystem.StopAllTweens(settings.ItemGroup.Entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!tweenSystem.HasTween(settings.ItemGroup.Entity))
|
||||
{
|
||||
settings.ItemContainer.anchoredPosition = Input.mousePosition;
|
||||
}
|
||||
|
||||
if (!input.Drag)
|
||||
{
|
||||
var slot = -1;
|
||||
var inventory = Entity.Null;
|
||||
var pos = EntityManager.HasComponent<Rigidbody2D>(entity)
|
||||
? EntityManager.GetComponentObject<Rigidbody2D>(entity).position
|
||||
: (Vector2)camera.ScreenToWorldPoint(e.ScreenPos, Camera.MonoOrStereoscopicEye.Mono);
|
||||
|
||||
Entities.ForEach(
|
||||
(ref SlotUiData slotUiData, ref OverEvent overEvent) =>
|
||||
{
|
||||
slot = slotUiData.Index;
|
||||
inventory = slotUiData.Inventory;
|
||||
});
|
||||
|
||||
if (inventory == Entity.Null || !EntityManager.Exists(inventory))
|
||||
{
|
||||
Entities.ForEach((InventoryWindowData windowData, ref OverEvent overEvent) => { inventory = windowData.Inventory; });
|
||||
}
|
||||
|
||||
var newEntity = PostUpdateCommands.CreateEntity();
|
||||
PostUpdateCommands.AddComponent(
|
||||
newEntity,
|
||||
new ItemDropEvent { Pos = pos, Item = e.Item, Inventory = inventory, ToSlot = slot, FromSlot = e.Slot });
|
||||
|
||||
PostUpdateCommands.RemoveComponent<ItemDragEvent>(entity);
|
||||
tweenSystem.StopAllTweens(settings.ItemGroup.Entity);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
settings.ItemCanvas.enabled = enableItemCanvasFlag;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/UI/ItemDraggingSystem.cs.meta
Normal file
3
Assets/Scripts/UI/ItemDraggingSystem.cs.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5d74462c835f474896f8104dcb98312f
|
||||
timeCreated: 1534079210
|
||||
49
Assets/Scripts/UI/SlotPartsData.cs
Normal file
49
Assets/Scripts/UI/SlotPartsData.cs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
using Assets.Scripts.UI;
|
||||
using Attributes;
|
||||
using System;
|
||||
using TMPro;
|
||||
using Unity.Entities;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace UI
|
||||
{
|
||||
public struct SlotPartsData : ISharedComponentData, IEquatable<SlotPartsData>
|
||||
{
|
||||
[RootComponent] public EventTrigger Trigger;
|
||||
public TextMeshProUGUI Amount;
|
||||
public Graphic Highlight;
|
||||
public SpriteImage Icon;
|
||||
public Image SlotIcon;
|
||||
public Graphic IconBackground;
|
||||
|
||||
public bool Equals(SlotPartsData other)
|
||||
{
|
||||
return Equals(Trigger, other.Trigger) &&
|
||||
Equals(Amount, other.Amount) &&
|
||||
Equals(Highlight, other.Highlight) &&
|
||||
Equals(Icon, other.Icon) &&
|
||||
Equals(SlotIcon, other.SlotIcon) &&
|
||||
Equals(IconBackground, other.IconBackground);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is SlotPartsData other && Equals(other);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hashCode = Trigger != null ? Trigger.GetHashCode() : 0;
|
||||
hashCode = (hashCode * 397) ^ (Amount != null ? Amount.GetHashCode() : 0);
|
||||
hashCode = (hashCode * 397) ^ (Highlight != null ? Highlight.GetHashCode() : 0);
|
||||
hashCode = (hashCode * 397) ^ (Icon != null ? Icon.GetHashCode() : 0);
|
||||
hashCode = (hashCode * 397) ^ (SlotIcon != null ? SlotIcon.GetHashCode() : 0);
|
||||
hashCode = (hashCode * 397) ^ (IconBackground != null ? IconBackground.GetHashCode() : 0);
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/UI/SlotPartsData.cs.meta
Normal file
3
Assets/Scripts/UI/SlotPartsData.cs.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ffc23ea9b9a940f68f6a0b82270d454c
|
||||
timeCreated: 1532255044
|
||||
9
Assets/Scripts/UI/SlotReference.cs
Normal file
9
Assets/Scripts/UI/SlotReference.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
using Unity.Entities;
|
||||
|
||||
namespace UI
|
||||
{
|
||||
public struct SlotReference : IBufferElementData
|
||||
{
|
||||
public Entity Slot;
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/UI/SlotReference.cs.meta
Normal file
3
Assets/Scripts/UI/SlotReference.cs.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6964f67671d844a599ccbc67b28a46dd
|
||||
timeCreated: 1534104420
|
||||
12
Assets/Scripts/UI/SlotUiData.cs
Normal file
12
Assets/Scripts/UI/SlotUiData.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
using DefaultNamespace;
|
||||
using Unity.Entities;
|
||||
|
||||
namespace UI
|
||||
{
|
||||
public struct SlotUiData : IComponentData
|
||||
{
|
||||
public Entity Inventory;
|
||||
public int Index;
|
||||
public bool1 SpecialSlot;
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/UI/SlotUiData.cs.meta
Normal file
3
Assets/Scripts/UI/SlotUiData.cs.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1ca432cd9fdb49dd9531dde94196e258
|
||||
timeCreated: 1534103244
|
||||
144
Assets/Scripts/UI/SpriteImage.cs
Normal file
144
Assets/Scripts/UI/SpriteImage.cs
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
using Trive.Assets.Scripts.Utils.Extensions;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Assets.Scripts.UI
|
||||
{
|
||||
public class SpriteImage : MaskableGraphic
|
||||
{
|
||||
protected static Material s_ETC1DefaultUI;
|
||||
|
||||
[SerializeField] private Sprite m_Sprite;
|
||||
|
||||
public static Material defaultETC1GraphicMaterial
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_ETC1DefaultUI == null)
|
||||
{
|
||||
s_ETC1DefaultUI = Canvas.GetETC1SupportedCanvasMaterial();
|
||||
}
|
||||
return s_ETC1DefaultUI;
|
||||
}
|
||||
}
|
||||
|
||||
public Sprite sprite
|
||||
{
|
||||
get => m_Sprite;
|
||||
set
|
||||
{
|
||||
if (m_Sprite != value)
|
||||
{
|
||||
m_Sprite = value;
|
||||
SetAllDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float pixelsPerUnit
|
||||
{
|
||||
get
|
||||
{
|
||||
float spritePixelsPerUnit = 100;
|
||||
if (sprite)
|
||||
{
|
||||
spritePixelsPerUnit = sprite.pixelsPerUnit;
|
||||
}
|
||||
|
||||
float referencePixelsPerUnit = 100;
|
||||
if (canvas)
|
||||
{
|
||||
referencePixelsPerUnit = canvas.referencePixelsPerUnit;
|
||||
}
|
||||
|
||||
return spritePixelsPerUnit / referencePixelsPerUnit;
|
||||
}
|
||||
}
|
||||
|
||||
public override Texture mainTexture
|
||||
{
|
||||
get
|
||||
{
|
||||
if (sprite == null)
|
||||
{
|
||||
if (material != null && material.mainTexture != null)
|
||||
{
|
||||
return material.mainTexture;
|
||||
}
|
||||
return s_WhiteTexture;
|
||||
}
|
||||
|
||||
return sprite.texture;
|
||||
}
|
||||
}
|
||||
|
||||
public override Material material
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Material != null)
|
||||
{
|
||||
return m_Material;
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
if (Application.isPlaying && sprite && sprite.associatedAlphaSplitTexture != null)
|
||||
{
|
||||
return defaultETC1GraphicMaterial;
|
||||
}
|
||||
#else
|
||||
if (sprite && sprite.associatedAlphaSplitTexture != null)
|
||||
return defaultETC1GraphicMaterial;
|
||||
#endif
|
||||
|
||||
return defaultMaterial;
|
||||
}
|
||||
|
||||
set { base.material = value; }
|
||||
}
|
||||
|
||||
protected override void OnPopulateMesh(VertexHelper toFill)
|
||||
{
|
||||
if (sprite == null)
|
||||
{
|
||||
base.OnPopulateMesh(toFill);
|
||||
return;
|
||||
}
|
||||
|
||||
toFill.Clear();
|
||||
var rect = GetPixelAdjustedRect();
|
||||
var vertecies = sprite.vertices;
|
||||
|
||||
if (vertecies.Length <= 0)
|
||||
{
|
||||
base.OnPopulateMesh(toFill);
|
||||
return;
|
||||
}
|
||||
|
||||
var bounds = new Rect(vertecies[0], Vector2.zero);
|
||||
for (var i = 1; i < vertecies.Length; i++)
|
||||
{
|
||||
bounds = bounds.Encapculate(vertecies[i]);
|
||||
}
|
||||
|
||||
var maxDist = Mathf.Max(bounds.width, bounds.height) * 0.5f;
|
||||
var triangles = sprite.triangles;
|
||||
var uv = sprite.uv;
|
||||
|
||||
for (var i = 0; i < vertecies.Length; i++)
|
||||
{
|
||||
toFill.AddVert(
|
||||
new UIVertex
|
||||
{
|
||||
position = (vertecies[i] - bounds.center) / maxDist * Mathf.Min(rect.width, rect.height) * 0.5f,
|
||||
color = color,
|
||||
uv0 = uv[i]
|
||||
});
|
||||
}
|
||||
|
||||
for (var i = 0; i < triangles.Length; i += 3)
|
||||
{
|
||||
toFill.AddTriangle(triangles[i], triangles[i + 1], triangles[i + 2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/UI/SpriteImage.cs.meta
Normal file
11
Assets/Scripts/UI/SpriteImage.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8addf2a500f392d4c9f256464b8e84e3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Scripts/UI/Tilemap.meta
Normal file
8
Assets/Scripts/UI/Tilemap.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: aef3ff665307dda41a292bfaebb079fe
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Scripts/UI/Tilemap/Brushes.meta
Normal file
8
Assets/Scripts/UI/Tilemap/Brushes.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 20cda7be1d474e4469429b7459ec716e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Scripts/UI/Tilemap/Brushes/Coordinate Brush.meta
Normal file
8
Assets/Scripts/UI/Tilemap/Brushes/Coordinate Brush.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2787f7307aeaaf348a734c189cdb4676
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 37b07ea36b1cbaa41aeda520548feef2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 527c1efaf8221b245b125c414bc61c37
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor
|
||||
{
|
||||
[CustomGridBrush(true, false, false, "Coordinate Brush")]
|
||||
public class CoordinateBrush : UnityEditor.Tilemaps.GridBrush {
|
||||
public int z = 0;
|
||||
|
||||
public override void Paint(GridLayout grid, GameObject brushTarget, Vector3Int position)
|
||||
{
|
||||
var zPosition = new Vector3Int(position.x, position.y, z);
|
||||
base.Paint(grid, brushTarget, zPosition);
|
||||
}
|
||||
|
||||
public override void Erase(GridLayout grid, GameObject brushTarget, Vector3Int position)
|
||||
{
|
||||
var zPosition = new Vector3Int(position.x, position.y, z);
|
||||
base.Erase(grid, brushTarget, zPosition);
|
||||
}
|
||||
|
||||
public override void FloodFill(GridLayout grid, GameObject brushTarget, Vector3Int position)
|
||||
{
|
||||
var zPosition = new Vector3Int(position.x, position.y, z);
|
||||
base.FloodFill(grid, brushTarget, zPosition);
|
||||
}
|
||||
|
||||
public override void BoxFill(GridLayout gridLayout, GameObject brushTarget, BoundsInt position)
|
||||
{
|
||||
var zPosition = new Vector3Int(position.x, position.y, z);
|
||||
position.position = zPosition;
|
||||
base.BoxFill(gridLayout, brushTarget, position);
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Create/Coordinate Brush")]
|
||||
public static void CreateBrush()
|
||||
{
|
||||
string path = EditorUtility.SaveFilePanelInProject("Save Coordinate Brush", "New Coordinate Brush", "asset", "Save Coordinate Brush", "Assets");
|
||||
|
||||
if (path == "")
|
||||
return;
|
||||
|
||||
AssetDatabase.CreateAsset(ScriptableObject.CreateInstance<CoordinateBrush>(), path);
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(CoordinateBrush))]
|
||||
public class CoordinateBrushEditor : UnityEditor.Tilemaps.GridBrushEditor
|
||||
{
|
||||
private CoordinateBrush coordinateBrush { get { return target as CoordinateBrush; } }
|
||||
|
||||
public override void PaintPreview(GridLayout grid, GameObject brushTarget, Vector3Int position)
|
||||
{
|
||||
var zPosition = new Vector3Int(position.x, position.y, coordinateBrush.z);
|
||||
base.PaintPreview(grid, brushTarget, zPosition);
|
||||
}
|
||||
|
||||
public override void OnPaintSceneGUI(GridLayout grid, GameObject brushTarget, BoundsInt position, GridBrushBase.Tool tool, bool executing)
|
||||
{
|
||||
base.OnPaintSceneGUI(grid, brushTarget, position, tool, executing);
|
||||
if (coordinateBrush.z != 0)
|
||||
{
|
||||
var zPosition = new Vector3Int(position.min.x, position.min.y, coordinateBrush.z);
|
||||
BoundsInt newPosition = new BoundsInt(zPosition, position.size);
|
||||
Vector3[] cellLocals = new Vector3[]
|
||||
{
|
||||
grid.CellToLocal(new Vector3Int(newPosition.min.x, newPosition.min.y, newPosition.min.z)),
|
||||
grid.CellToLocal(new Vector3Int(newPosition.max.x, newPosition.min.y, newPosition.min.z)),
|
||||
grid.CellToLocal(new Vector3Int(newPosition.max.x, newPosition.max.y, newPosition.min.z)),
|
||||
grid.CellToLocal(new Vector3Int(newPosition.min.x, newPosition.max.y, newPosition.min.z))
|
||||
};
|
||||
|
||||
Handles.color = Color.blue;
|
||||
int i = 0;
|
||||
for (int j = cellLocals.Length - 1; i < cellLocals.Length; j = i++)
|
||||
{
|
||||
Handles.DrawLine(cellLocals[j], cellLocals[i]);
|
||||
}
|
||||
}
|
||||
|
||||
var labelText = "Pos: " + new Vector3Int(position.x, position.y, coordinateBrush.z);
|
||||
if (position.size.x > 1 || position.size.y > 1) {
|
||||
labelText += " Size: " + new Vector2Int(position.size.x, position.size.y);
|
||||
}
|
||||
|
||||
Handles.Label(grid.CellToWorld(new Vector3Int(position.x, position.y, coordinateBrush.z)), labelText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d283e353fe1f4c34f8ac458281740fb4
|
||||
timeCreated: 1499149770
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Scripts/UI/Tilemap/Brushes/GameObject Brush.meta
Normal file
8
Assets/Scripts/UI/Tilemap/Brushes/GameObject Brush.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 381ad9fa709caf04197e5a8b24a7d6b2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: becdef7ff3038f844a171e247f575688
|
||||
folderAsset: yes
|
||||
timeCreated: 1501789865
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 62c56be364c00f14ba85c5d3f280447c
|
||||
folderAsset: yes
|
||||
timeCreated: 1501789982
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,489 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Tilemaps;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace UnityEditor
|
||||
{
|
||||
[CustomGridBrush(true, false, false, "GameObject Brush")]
|
||||
public class GameObjectBrush : GridBrushBase
|
||||
{
|
||||
[SerializeField]
|
||||
[HideInInspector]
|
||||
private BrushCell[] m_Cells;
|
||||
|
||||
[SerializeField]
|
||||
[HideInInspector]
|
||||
private Vector3Int m_Size;
|
||||
|
||||
[SerializeField]
|
||||
[HideInInspector]
|
||||
private Vector3Int m_Pivot;
|
||||
|
||||
public Vector3Int size { get { return m_Size; } set { m_Size = value; SizeUpdated(); } }
|
||||
public Vector3Int pivot { get { return m_Pivot; } set { m_Pivot = value; } }
|
||||
public BrushCell[] cells { get { return m_Cells; } }
|
||||
public int cellCount { get { return m_Cells != null ? m_Cells.Length : 0; } }
|
||||
|
||||
public GameObjectBrush()
|
||||
{
|
||||
Init(Vector3Int.one, Vector3Int.zero);
|
||||
SizeUpdated();
|
||||
}
|
||||
|
||||
public void Init(Vector3Int size)
|
||||
{
|
||||
Init(size, Vector3Int.zero);
|
||||
SizeUpdated();
|
||||
}
|
||||
|
||||
public void Init(Vector3Int size, Vector3Int pivot)
|
||||
{
|
||||
m_Size = size;
|
||||
m_Pivot = pivot;
|
||||
SizeUpdated();
|
||||
}
|
||||
|
||||
public override void Paint(GridLayout gridLayout, GameObject brushTarget, Vector3Int position)
|
||||
{
|
||||
// Do not allow editing palettes
|
||||
if (brushTarget.layer == 31)
|
||||
return;
|
||||
|
||||
Vector3Int min = position - pivot;
|
||||
BoundsInt bounds = new BoundsInt(min, m_Size);
|
||||
BoxFill(gridLayout, brushTarget, bounds);
|
||||
}
|
||||
|
||||
private void PaintCell(GridLayout grid, Vector3Int position, Transform parent, BrushCell cell)
|
||||
{
|
||||
if (cell.gameObject != null)
|
||||
{
|
||||
SetSceneCell(grid, parent, position, cell.gameObject, cell.offset, cell.scale, cell.orientation);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Erase(GridLayout gridLayout, GameObject brushTarget, Vector3Int position)
|
||||
{
|
||||
// Do not allow editing palettes
|
||||
if (brushTarget.layer == 31)
|
||||
return;
|
||||
|
||||
Vector3Int min = position - pivot;
|
||||
BoundsInt bounds = new BoundsInt(min, m_Size);
|
||||
BoxErase(gridLayout, brushTarget, bounds);
|
||||
}
|
||||
|
||||
private void EraseCell(GridLayout grid, Vector3Int position, Transform parent)
|
||||
{
|
||||
ClearSceneCell(grid, parent, position);
|
||||
}
|
||||
|
||||
public override void BoxFill(GridLayout gridLayout, GameObject brushTarget, BoundsInt position)
|
||||
{
|
||||
// Do not allow editing palettes
|
||||
if (brushTarget.layer == 31)
|
||||
return;
|
||||
|
||||
if (brushTarget == null)
|
||||
return;
|
||||
|
||||
foreach (Vector3Int location in position.allPositionsWithin)
|
||||
{
|
||||
Vector3Int local = location - position.min;
|
||||
BrushCell cell = m_Cells[GetCellIndexWrapAround(local.x, local.y, local.z)];
|
||||
PaintCell(gridLayout, location, brushTarget.transform, cell);
|
||||
}
|
||||
}
|
||||
|
||||
public override void BoxErase(GridLayout gridLayout, GameObject brushTarget, BoundsInt position)
|
||||
{
|
||||
// Do not allow editing palettes
|
||||
if (brushTarget.layer == 31)
|
||||
return;
|
||||
|
||||
if (brushTarget == null)
|
||||
return;
|
||||
|
||||
foreach (Vector3Int location in position.allPositionsWithin)
|
||||
{
|
||||
EraseCell(gridLayout, location, brushTarget.transform);
|
||||
}
|
||||
}
|
||||
|
||||
public override void FloodFill(GridLayout gridLayout, GameObject brushTarget, Vector3Int position)
|
||||
{
|
||||
Debug.LogWarning("FloodFill not supported");
|
||||
}
|
||||
|
||||
public override void Rotate(RotationDirection direction, Grid.CellLayout layout)
|
||||
{
|
||||
Vector3Int oldSize = m_Size;
|
||||
BrushCell[] oldCells = m_Cells.Clone() as BrushCell[];
|
||||
size = new Vector3Int(oldSize.y, oldSize.x, oldSize.z);
|
||||
BoundsInt oldBounds = new BoundsInt(Vector3Int.zero, oldSize);
|
||||
|
||||
foreach (Vector3Int oldPos in oldBounds.allPositionsWithin)
|
||||
{
|
||||
int newX = direction == RotationDirection.Clockwise ? oldSize.y - oldPos.y - 1 : oldPos.y;
|
||||
int newY = direction == RotationDirection.Clockwise ? oldPos.x : oldSize.x - oldPos.x - 1;
|
||||
int toIndex = GetCellIndex(newX, newY, oldPos.z);
|
||||
int fromIndex = GetCellIndex(oldPos.x, oldPos.y, oldPos.z, oldSize.x, oldSize.y, oldSize.z);
|
||||
m_Cells[toIndex] = oldCells[fromIndex];
|
||||
}
|
||||
|
||||
int newPivotX = direction == RotationDirection.Clockwise ? oldSize.y - pivot.y - 1 : pivot.y;
|
||||
int newPivotY = direction == RotationDirection.Clockwise ? pivot.x : oldSize.x - pivot.x - 1;
|
||||
pivot = new Vector3Int(newPivotX, newPivotY, pivot.z);
|
||||
|
||||
Matrix4x4 rotation = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, direction == RotationDirection.Clockwise ? 90f : -90f), Vector3.one);
|
||||
Quaternion orientation = Quaternion.Euler(0f, 0f, direction == RotationDirection.Clockwise ? 90f : -90f);
|
||||
foreach (BrushCell cell in m_Cells)
|
||||
{
|
||||
cell.offset = rotation * cell.offset;
|
||||
cell.orientation = cell.orientation * orientation;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Flip(FlipAxis flip, Grid.CellLayout layout)
|
||||
{
|
||||
if (flip == FlipAxis.X)
|
||||
FlipX();
|
||||
else
|
||||
FlipY();
|
||||
}
|
||||
|
||||
public override void Pick(GridLayout gridLayout, GameObject brushTarget, BoundsInt position, Vector3Int pickStart)
|
||||
{
|
||||
// Do not allow editing palettes
|
||||
if (brushTarget.layer == 31)
|
||||
return;
|
||||
|
||||
Reset();
|
||||
UpdateSizeAndPivot(new Vector3Int(position.size.x, position.size.y, 1), new Vector3Int(pickStart.x, pickStart.y, 0));
|
||||
|
||||
foreach (Vector3Int pos in position.allPositionsWithin)
|
||||
{
|
||||
Vector3Int brushPosition = new Vector3Int(pos.x - position.x, pos.y - position.y, 0);
|
||||
PickCell(pos, brushPosition, gridLayout, brushTarget.transform);
|
||||
}
|
||||
}
|
||||
|
||||
private void PickCell(Vector3Int position, Vector3Int brushPosition, GridLayout grid, Transform parent)
|
||||
{
|
||||
if (parent != null)
|
||||
{
|
||||
Vector3 cellCenter = grid.LocalToWorld(grid.CellToLocalInterpolated(position + new Vector3(.5f, .5f, .5f)));
|
||||
GameObject go = GetObjectInCell(grid, parent, position);
|
||||
|
||||
if (go != null)
|
||||
{
|
||||
Object prefab = PrefabUtility.GetCorrespondingObjectFromSource(go);
|
||||
|
||||
if (prefab)
|
||||
{
|
||||
SetGameObject(brushPosition, (GameObject) prefab);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameObject newInstance = Instantiate(go);
|
||||
newInstance.hideFlags = HideFlags.HideAndDontSave;
|
||||
SetGameObject(brushPosition, newInstance);
|
||||
}
|
||||
|
||||
SetOffset(brushPosition, go.transform.position - cellCenter);
|
||||
SetScale(brushPosition, go.transform.localScale);
|
||||
SetOrientation(brushPosition, go.transform.localRotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void MoveStart(GridLayout gridLayout, GameObject brushTarget, BoundsInt position)
|
||||
{
|
||||
// Do not allow editing palettes
|
||||
if (brushTarget.layer == 31)
|
||||
return;
|
||||
|
||||
Reset();
|
||||
UpdateSizeAndPivot(new Vector3Int(position.size.x, position.size.y, 1), Vector3Int.zero);
|
||||
|
||||
if (brushTarget != null)
|
||||
{
|
||||
foreach (Vector3Int pos in position.allPositionsWithin)
|
||||
{
|
||||
Vector3Int brushPosition = new Vector3Int(pos.x - position.x, pos.y - position.y, 0);
|
||||
PickCell(pos, brushPosition, gridLayout, brushTarget.transform);
|
||||
ClearSceneCell(gridLayout, brushTarget.transform, brushPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void MoveEnd(GridLayout gridLayout, GameObject brushTarget, BoundsInt position)
|
||||
{
|
||||
// Do not allow editing palettes
|
||||
if (brushTarget.layer == 31)
|
||||
return;
|
||||
|
||||
Paint(gridLayout, brushTarget, position.min);
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
foreach (var cell in m_Cells)
|
||||
{
|
||||
if (cell.gameObject != null && !EditorUtility.IsPersistent(cell.gameObject))
|
||||
{
|
||||
DestroyImmediate(cell.gameObject);
|
||||
}
|
||||
}
|
||||
UpdateSizeAndPivot(Vector3Int.one, Vector3Int.zero);
|
||||
}
|
||||
|
||||
private void FlipX()
|
||||
{
|
||||
BrushCell[] oldCells = m_Cells.Clone() as BrushCell[];
|
||||
BoundsInt oldBounds = new BoundsInt(Vector3Int.zero, m_Size);
|
||||
|
||||
foreach (Vector3Int oldPos in oldBounds.allPositionsWithin)
|
||||
{
|
||||
int newX = m_Size.x - oldPos.x - 1;
|
||||
int toIndex = GetCellIndex(newX, oldPos.y, oldPos.z);
|
||||
int fromIndex = GetCellIndex(oldPos);
|
||||
m_Cells[toIndex] = oldCells[fromIndex];
|
||||
}
|
||||
|
||||
int newPivotX = m_Size.x - pivot.x - 1;
|
||||
pivot = new Vector3Int(newPivotX, pivot.y, pivot.z);
|
||||
Matrix4x4 flip = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(-1f, 1f, 1f));
|
||||
Quaternion orientation = Quaternion.Euler(0f, 0f, -180f);
|
||||
|
||||
foreach (BrushCell cell in m_Cells)
|
||||
{
|
||||
Vector3 oldOffset = cell.offset;
|
||||
cell.offset = flip * oldOffset;
|
||||
cell.orientation = cell.orientation*orientation;
|
||||
}
|
||||
}
|
||||
|
||||
private void FlipY()
|
||||
{
|
||||
BrushCell[] oldCells = m_Cells.Clone() as BrushCell[];
|
||||
BoundsInt oldBounds = new BoundsInt(Vector3Int.zero, m_Size);
|
||||
|
||||
foreach (Vector3Int oldPos in oldBounds.allPositionsWithin)
|
||||
{
|
||||
int newY = m_Size.y - oldPos.y - 1;
|
||||
int toIndex = GetCellIndex(oldPos.x, newY, oldPos.z);
|
||||
int fromIndex = GetCellIndex(oldPos);
|
||||
m_Cells[toIndex] = oldCells[fromIndex];
|
||||
}
|
||||
|
||||
int newPivotY = m_Size.y - pivot.y - 1;
|
||||
pivot = new Vector3Int(pivot.x, newPivotY, pivot.z);
|
||||
Matrix4x4 flip = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1f, -1f, 1f));
|
||||
Quaternion orientation = Quaternion.Euler(0f, 0f, -180f);
|
||||
foreach (BrushCell cell in m_Cells)
|
||||
{
|
||||
Vector3 oldOffset = cell.offset;
|
||||
cell.offset = flip * oldOffset;
|
||||
cell.orientation = cell.orientation * orientation;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateSizeAndPivot(Vector3Int size, Vector3Int pivot)
|
||||
{
|
||||
m_Size = size;
|
||||
m_Pivot = pivot;
|
||||
SizeUpdated();
|
||||
}
|
||||
|
||||
public void SetGameObject(Vector3Int position, GameObject go)
|
||||
{
|
||||
if (ValidateCellPosition(position))
|
||||
m_Cells[GetCellIndex(position)].gameObject = go;
|
||||
}
|
||||
|
||||
public void SetOffset(Vector3Int position, Vector3 offset)
|
||||
{
|
||||
if (ValidateCellPosition(position))
|
||||
m_Cells[GetCellIndex(position)].offset = offset;
|
||||
}
|
||||
|
||||
public void SetOrientation(Vector3Int position, Quaternion orientation)
|
||||
{
|
||||
if (ValidateCellPosition(position))
|
||||
m_Cells[GetCellIndex(position)].orientation = orientation;
|
||||
}
|
||||
|
||||
public void SetScale(Vector3Int position, Vector3 scale)
|
||||
{
|
||||
if (ValidateCellPosition(position))
|
||||
m_Cells[GetCellIndex(position)].scale = scale;
|
||||
}
|
||||
|
||||
public int GetCellIndex(Vector3Int brushPosition)
|
||||
{
|
||||
return GetCellIndex(brushPosition.x, brushPosition.y, brushPosition.z);
|
||||
}
|
||||
|
||||
public int GetCellIndex(int x, int y, int z)
|
||||
{
|
||||
return x + m_Size.x * y + m_Size.x * m_Size.y * z;
|
||||
}
|
||||
|
||||
public int GetCellIndex(int x, int y, int z, int sizex, int sizey, int sizez)
|
||||
{
|
||||
return x + sizex * y + sizex * sizey * z;
|
||||
}
|
||||
|
||||
public int GetCellIndexWrapAround(int x, int y, int z)
|
||||
{
|
||||
return (x % m_Size.x) + m_Size.x * (y % m_Size.y) + m_Size.x * m_Size.y * (z % m_Size.z);
|
||||
}
|
||||
|
||||
private static GameObject GetObjectInCell(GridLayout grid, Transform parent, Vector3Int position)
|
||||
{
|
||||
int childCount = parent.childCount;
|
||||
Vector3 min = grid.LocalToWorld(grid.CellToLocalInterpolated(position));
|
||||
Vector3 max = grid.LocalToWorld(grid.CellToLocalInterpolated(position + Vector3Int.one));
|
||||
|
||||
// Infinite bounds on Z for 2D convenience
|
||||
min = new Vector3(min.x, min.y, float.MinValue);
|
||||
max = new Vector3(max.x, max.y, float.MaxValue);
|
||||
|
||||
Bounds bounds = new Bounds((max + min) * .5f, max - min);
|
||||
|
||||
for (int i = 0; i < childCount; i++)
|
||||
{
|
||||
Transform child = parent.GetChild(i);
|
||||
if (bounds.Contains(child.position))
|
||||
return child.gameObject;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool ValidateCellPosition(Vector3Int position)
|
||||
{
|
||||
var valid =
|
||||
position.x >= 0 && position.x < size.x &&
|
||||
position.y >= 0 && position.y < size.y &&
|
||||
position.z >= 0 && position.z < size.z;
|
||||
if (!valid)
|
||||
throw new ArgumentException(string.Format("Position {0} is an invalid cell position. Valid range is between [{1}, {2}).", position, Vector3Int.zero, size));
|
||||
return valid;
|
||||
}
|
||||
|
||||
private void SizeUpdated()
|
||||
{
|
||||
m_Cells = new BrushCell[m_Size.x * m_Size.y * m_Size.z];
|
||||
BoundsInt bounds = new BoundsInt(Vector3Int.zero, m_Size);
|
||||
foreach (Vector3Int pos in bounds.allPositionsWithin)
|
||||
{
|
||||
m_Cells[GetCellIndex(pos)] = new BrushCell();
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetSceneCell(GridLayout grid, Transform parent, Vector3Int position, GameObject go, Vector3 offset, Vector3 scale, Quaternion orientation)
|
||||
{
|
||||
if (parent == null || go == null)
|
||||
return;
|
||||
|
||||
GameObject instance = null;
|
||||
if (PrefabUtility.GetPrefabType(go) == PrefabType.Prefab)
|
||||
{
|
||||
instance = (GameObject) PrefabUtility.InstantiatePrefab(go);
|
||||
}
|
||||
else
|
||||
{
|
||||
instance = Instantiate(go);
|
||||
instance.hideFlags = HideFlags.None;
|
||||
instance.name = go.name;
|
||||
}
|
||||
|
||||
Undo.RegisterCreatedObjectUndo(instance, "Paint GameObject");
|
||||
instance.transform.SetParent(parent);
|
||||
instance.transform.position = grid.LocalToWorld(grid.CellToLocalInterpolated(new Vector3Int(position.x, position.y, position.z) + new Vector3(.5f, .5f, .5f)));
|
||||
instance.transform.localRotation = orientation;
|
||||
instance.transform.localScale = scale;
|
||||
instance.transform.Translate(offset);
|
||||
}
|
||||
|
||||
private static void ClearSceneCell(GridLayout grid, Transform parent, Vector3Int position)
|
||||
{
|
||||
if (parent == null)
|
||||
return;
|
||||
|
||||
GameObject erased = GetObjectInCell(grid, parent, new Vector3Int(position.x, position.y, position.z));
|
||||
if (erased != null)
|
||||
Undo.DestroyObjectImmediate(erased);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hash = 0;
|
||||
unchecked
|
||||
{
|
||||
foreach (var cell in cells)
|
||||
{
|
||||
hash = hash * 33 + cell.GetHashCode();
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class BrushCell
|
||||
{
|
||||
public GameObject gameObject { get { return m_GameObject; } set { m_GameObject = value; } }
|
||||
public Vector3 offset { get { return m_Offset; } set { m_Offset = value; } }
|
||||
public Vector3 scale { get { return m_Scale; } set { m_Scale = value; } }
|
||||
public Quaternion orientation { get { return m_Orientation; } set { m_Orientation = value; } }
|
||||
|
||||
[SerializeField]
|
||||
private GameObject m_GameObject;
|
||||
[SerializeField]
|
||||
Vector3 m_Offset = Vector3.zero;
|
||||
[SerializeField]
|
||||
Vector3 m_Scale = Vector3.one;
|
||||
[SerializeField]
|
||||
Quaternion m_Orientation = Quaternion.identity;
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hash = 0;
|
||||
unchecked
|
||||
{
|
||||
hash = gameObject != null ? gameObject.GetInstanceID() : 0;
|
||||
hash = hash * 33 + m_Offset.GetHashCode();
|
||||
hash = hash * 33 + m_Scale.GetHashCode();
|
||||
hash = hash * 33 + m_Orientation.GetHashCode();
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(GameObjectBrush))]
|
||||
public class GameObjectBrushEditor : UnityEditor.Tilemaps.GridBrushEditorBase
|
||||
{
|
||||
public GameObjectBrush brush { get { return target as GameObjectBrush; } }
|
||||
|
||||
public override void OnPaintSceneGUI(GridLayout gridLayout, GameObject brushTarget, BoundsInt position, GridBrushBase.Tool tool, bool executing)
|
||||
{
|
||||
BoundsInt gizmoRect = position;
|
||||
|
||||
if (tool == GridBrushBase.Tool.Paint || tool == GridBrushBase.Tool.Erase)
|
||||
gizmoRect = new BoundsInt(position.min - brush.pivot, brush.size);
|
||||
|
||||
base.OnPaintSceneGUI(gridLayout, brushTarget, gizmoRect, tool, executing);
|
||||
}
|
||||
|
||||
public override void OnPaintInspectorGUI()
|
||||
{
|
||||
GUILayout.Label("Pick, paint and erase GameObject(s) in the scene.");
|
||||
GUILayout.Label("Limited to children of the currently selected GameObject.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0abded712ad706044a53ef292972edbb
|
||||
timeCreated: 1501700935
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/Brushes/Line Brush.meta
Normal file
10
Assets/Scripts/UI/Tilemap/Brushes/Line Brush.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ddf6fb480373a4b4babf2bd106dd48d8
|
||||
folderAsset: yes
|
||||
timeCreated: 1499149753
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/Brushes/Line Brush/Scripts.meta
Normal file
10
Assets/Scripts/UI/Tilemap/Brushes/Line Brush/Scripts.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6a7de8b7c9f16a54abb1f4e4b4dda454
|
||||
folderAsset: yes
|
||||
timeCreated: 1499149780
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a4ce1d57936070949bdd366b4d13335f
|
||||
folderAsset: yes
|
||||
timeCreated: 1499149785
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Tilemaps;
|
||||
using System.Linq;
|
||||
|
||||
namespace UnityEditor
|
||||
{
|
||||
[CustomGridBrush(true, false, false, "Line Brush")]
|
||||
public class LineBrush : UnityEditor.Tilemaps.GridBrush
|
||||
{
|
||||
public bool lineStartActive = false;
|
||||
public bool fillGaps = false;
|
||||
public Vector3Int lineStart = Vector3Int.zero;
|
||||
|
||||
public override void Paint(GridLayout grid, GameObject brushTarget, Vector3Int position)
|
||||
{
|
||||
if (lineStartActive)
|
||||
{
|
||||
Vector2Int startPos = new Vector2Int(lineStart.x, lineStart.y);
|
||||
Vector2Int endPos = new Vector2Int(position.x, position.y);
|
||||
if (startPos == endPos)
|
||||
base.Paint(grid, brushTarget, position);
|
||||
else
|
||||
{
|
||||
foreach (var point in GetPointsOnLine(startPos, endPos, fillGaps))
|
||||
{
|
||||
Vector3Int paintPos = new Vector3Int(point.x, point.y, position.z);
|
||||
base.Paint(grid, brushTarget, paintPos);
|
||||
}
|
||||
}
|
||||
lineStartActive = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
lineStart = position;
|
||||
lineStartActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Create/Line Brush")]
|
||||
public static void CreateBrush()
|
||||
{
|
||||
string path = EditorUtility.SaveFilePanelInProject("Save Line Brush", "New Line Brush", "asset", "Save Line Brush", "Assets");
|
||||
|
||||
if (path == "")
|
||||
return;
|
||||
|
||||
AssetDatabase.CreateAsset(ScriptableObject.CreateInstance<LineBrush>(), path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Added option to fill gaps for continuous lines.
|
||||
/// </summary>
|
||||
public static IEnumerable<Vector2Int> GetPointsOnLine(Vector2Int startPos, Vector2Int endPos, bool fillGaps)
|
||||
{
|
||||
var points = GetPointsOnLine(startPos, endPos);
|
||||
if (fillGaps)
|
||||
{
|
||||
var rise = endPos.y - startPos.y;
|
||||
var run = endPos.x - startPos.x;
|
||||
|
||||
if (rise != 0 || run != 0)
|
||||
{
|
||||
var extraStart = startPos;
|
||||
var extraEnd = endPos;
|
||||
|
||||
|
||||
if (Mathf.Abs(rise) >= Mathf.Abs(run))
|
||||
{
|
||||
// up
|
||||
if (rise > 0)
|
||||
{
|
||||
extraStart.y += 1;
|
||||
extraEnd.y += 1;
|
||||
}
|
||||
// down
|
||||
else // rise < 0
|
||||
{
|
||||
|
||||
extraStart.y -= 1;
|
||||
extraEnd.y -= 1;
|
||||
}
|
||||
}
|
||||
else // Mathf.Abs(rise) < Mathf.Abs(run)
|
||||
{
|
||||
|
||||
// right
|
||||
if (run > 0)
|
||||
{
|
||||
extraStart.x += 1;
|
||||
extraEnd.x += 1;
|
||||
}
|
||||
// left
|
||||
else // run < 0
|
||||
{
|
||||
extraStart.x -= 1;
|
||||
extraEnd.x -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
var extraPoints = GetPointsOnLine(extraStart, extraEnd);
|
||||
extraPoints = extraPoints.Except(new[] { extraEnd });
|
||||
points = points.Union(extraPoints);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
// http://ericw.ca/notes/bresenhams-line-algorithm-in-csharp.html
|
||||
public static IEnumerable<Vector2Int> GetPointsOnLine(Vector2Int p1, Vector2Int p2)
|
||||
{
|
||||
int x0 = p1.x;
|
||||
int y0 = p1.y;
|
||||
int x1 = p2.x;
|
||||
int y1 = p2.y;
|
||||
|
||||
bool steep = Math.Abs(y1 - y0) > Math.Abs(x1 - x0);
|
||||
if (steep)
|
||||
{
|
||||
int t;
|
||||
t = x0; // swap x0 and y0
|
||||
x0 = y0;
|
||||
y0 = t;
|
||||
t = x1; // swap x1 and y1
|
||||
x1 = y1;
|
||||
y1 = t;
|
||||
}
|
||||
if (x0 > x1)
|
||||
{
|
||||
int t;
|
||||
t = x0; // swap x0 and x1
|
||||
x0 = x1;
|
||||
x1 = t;
|
||||
t = y0; // swap y0 and y1
|
||||
y0 = y1;
|
||||
y1 = t;
|
||||
}
|
||||
int dx = x1 - x0;
|
||||
int dy = Math.Abs(y1 - y0);
|
||||
int error = dx / 2;
|
||||
int ystep = (y0 < y1) ? 1 : -1;
|
||||
int y = y0;
|
||||
for (int x = x0; x <= x1; x++)
|
||||
{
|
||||
yield return new Vector2Int((steep ? y : x), (steep ? x : y));
|
||||
error = error - dy;
|
||||
if (error < 0)
|
||||
{
|
||||
y += ystep;
|
||||
error += dx;
|
||||
}
|
||||
}
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(LineBrush))]
|
||||
public class LineBrushEditor : UnityEditor.Tilemaps.GridBrushEditor
|
||||
{
|
||||
private LineBrush lineBrush { get { return target as LineBrush; } }
|
||||
|
||||
public override void OnPaintSceneGUI(GridLayout grid, GameObject brushTarget, BoundsInt position, GridBrushBase.Tool tool, bool executing)
|
||||
{
|
||||
base.OnPaintSceneGUI(grid, brushTarget, position, tool, executing);
|
||||
if (lineBrush.lineStartActive)
|
||||
{
|
||||
Tilemap tilemap = brushTarget.GetComponent<Tilemap>();
|
||||
if (tilemap != null)
|
||||
tilemap.ClearAllEditorPreviewTiles();
|
||||
|
||||
// Draw preview tiles for tilemap
|
||||
Vector2Int startPos = new Vector2Int(lineBrush.lineStart.x, lineBrush.lineStart.y);
|
||||
Vector2Int endPos = new Vector2Int(position.x, position.y);
|
||||
if (startPos == endPos)
|
||||
PaintPreview(grid, brushTarget, position.min);
|
||||
else
|
||||
{
|
||||
foreach (var point in LineBrush.GetPointsOnLine(startPos, endPos, lineBrush.fillGaps))
|
||||
{
|
||||
Vector3Int paintPos = new Vector3Int(point.x, point.y, position.z);
|
||||
PaintPreview(grid, brushTarget, paintPos);
|
||||
}
|
||||
}
|
||||
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
{
|
||||
var min = lineBrush.lineStart;
|
||||
var max = lineBrush.lineStart + position.size;
|
||||
|
||||
// Draws a box on the picked starting position
|
||||
GL.PushMatrix();
|
||||
GL.MultMatrix(GUI.matrix);
|
||||
GL.Begin(GL.LINES);
|
||||
Handles.color = Color.blue;
|
||||
Handles.DrawLine(new Vector3(min.x, min.y, min.z), new Vector3(max.x, min.y, min.z));
|
||||
Handles.DrawLine(new Vector3(max.x, min.y, min.z), new Vector3(max.x, max.y, min.z));
|
||||
Handles.DrawLine(new Vector3(max.x, max.y, min.z), new Vector3(min.x, max.y, min.z));
|
||||
Handles.DrawLine(new Vector3(min.x, max.y, min.z), new Vector3(min.x, min.y, min.z));
|
||||
GL.End();
|
||||
GL.PopMatrix();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6210598a979f8724a8dac4531c428889
|
||||
timeCreated: 1499149789
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/Brushes/Prefab Brush.meta
Normal file
10
Assets/Scripts/UI/Tilemap/Brushes/Prefab Brush.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9b73c833515e70440a2222f774104211
|
||||
folderAsset: yes
|
||||
timeCreated: 1501789833
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/Brushes/Prefab Brush/Scripts.meta
Normal file
10
Assets/Scripts/UI/Tilemap/Brushes/Prefab Brush/Scripts.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 090e78558c17f064eae502998e2f22fb
|
||||
folderAsset: yes
|
||||
timeCreated: 1501789849
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 642e946f97259c640b3a047a57944ed9
|
||||
folderAsset: yes
|
||||
timeCreated: 1501789995
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor
|
||||
{
|
||||
[CreateAssetMenu]
|
||||
[CustomGridBrush(false, true, false, "Prefab Brush")]
|
||||
public class PrefabBrush : GridBrushBase
|
||||
{
|
||||
private const float k_PerlinOffset = 100000f;
|
||||
public GameObject[] m_Prefabs;
|
||||
public float m_PerlinScale = 0.5f;
|
||||
public int m_Z;
|
||||
|
||||
public override void Paint(GridLayout grid, GameObject brushTarget, Vector3Int position)
|
||||
{
|
||||
// Do not allow editing palettes
|
||||
if (brushTarget.layer == 31)
|
||||
return;
|
||||
|
||||
int index = Mathf.Clamp(Mathf.FloorToInt(GetPerlinValue(position, m_PerlinScale, k_PerlinOffset)*m_Prefabs.Length), 0, m_Prefabs.Length - 1);
|
||||
GameObject prefab = m_Prefabs[index];
|
||||
GameObject instance = (GameObject) PrefabUtility.InstantiatePrefab(prefab);
|
||||
if (instance != null)
|
||||
{
|
||||
Undo.MoveGameObjectToScene(instance, brushTarget.scene, "Paint Prefabs");
|
||||
Undo.RegisterCreatedObjectUndo((Object)instance, "Paint Prefabs");
|
||||
instance.transform.SetParent(brushTarget.transform);
|
||||
instance.transform.position = grid.LocalToWorld(grid.CellToLocalInterpolated(new Vector3Int(position.x, position.y, m_Z) + new Vector3(.5f, .5f, .5f)));
|
||||
}
|
||||
}
|
||||
|
||||
public override void Erase(GridLayout grid, GameObject brushTarget, Vector3Int position)
|
||||
{
|
||||
// Do not allow editing palettes
|
||||
if (brushTarget.layer == 31)
|
||||
return;
|
||||
|
||||
Transform erased = GetObjectInCell(grid, brushTarget.transform, new Vector3Int(position.x, position.y, m_Z));
|
||||
if (erased != null)
|
||||
Undo.DestroyObjectImmediate(erased.gameObject);
|
||||
}
|
||||
|
||||
private static Transform GetObjectInCell(GridLayout grid, Transform parent, Vector3Int position)
|
||||
{
|
||||
int childCount = parent.childCount;
|
||||
Vector3 min = grid.LocalToWorld(grid.CellToLocalInterpolated(position));
|
||||
Vector3 max = grid.LocalToWorld(grid.CellToLocalInterpolated(position + Vector3Int.one));
|
||||
Bounds bounds = new Bounds((max + min)*.5f, max - min);
|
||||
|
||||
for (int i = 0; i < childCount; i++)
|
||||
{
|
||||
Transform child = parent.GetChild(i);
|
||||
if (bounds.Contains(child.position))
|
||||
return child;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static float GetPerlinValue(Vector3Int position, float scale, float offset)
|
||||
{
|
||||
return Mathf.PerlinNoise((position.x + offset)*scale, (position.y + offset)*scale);
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(PrefabBrush))]
|
||||
public class PrefabBrushEditor : UnityEditor.Tilemaps.GridBrushEditorBase
|
||||
{
|
||||
private PrefabBrush prefabBrush { get { return target as PrefabBrush; } }
|
||||
|
||||
private SerializedProperty m_Prefabs;
|
||||
private SerializedObject m_SerializedObject;
|
||||
|
||||
protected void OnEnable()
|
||||
{
|
||||
m_SerializedObject = new SerializedObject(target);
|
||||
m_Prefabs = m_SerializedObject.FindProperty("m_Prefabs");
|
||||
}
|
||||
|
||||
public override void OnPaintInspectorGUI()
|
||||
{
|
||||
m_SerializedObject.UpdateIfRequiredOrScript();
|
||||
prefabBrush.m_PerlinScale = EditorGUILayout.Slider("Perlin Scale", prefabBrush.m_PerlinScale, 0.001f, 0.999f);
|
||||
prefabBrush.m_Z = EditorGUILayout.IntField("Position Z", prefabBrush.m_Z);
|
||||
|
||||
EditorGUILayout.PropertyField(m_Prefabs, true);
|
||||
m_SerializedObject.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2d5751a2c961df945a34295ccf5e576d
|
||||
timeCreated: 1501681786
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/Brushes/Random Brush.meta
Normal file
10
Assets/Scripts/UI/Tilemap/Brushes/Random Brush.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8dee42ba30f712246852f41830cedbef
|
||||
folderAsset: yes
|
||||
timeCreated: 1499223176
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/Brushes/Random Brush/Scripts.meta
Normal file
10
Assets/Scripts/UI/Tilemap/Brushes/Random Brush/Scripts.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d352e5b4c56a76e4d99fc48256bbc67e
|
||||
folderAsset: yes
|
||||
timeCreated: 1499223198
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 762d145b6139de6478fcc2998702d839
|
||||
folderAsset: yes
|
||||
timeCreated: 1499223228
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Tilemaps;
|
||||
|
||||
namespace UnityEditor
|
||||
{
|
||||
[CustomGridBrush(false, true, false, "Random Brush")]
|
||||
public class RandomBrush : UnityEditor.Tilemaps.GridBrush
|
||||
{
|
||||
public TileBase[] randomTiles;
|
||||
|
||||
public override void Paint(GridLayout grid, GameObject brushTarget, Vector3Int position)
|
||||
{
|
||||
if (randomTiles != null && randomTiles.Length > 0)
|
||||
{
|
||||
if (brushTarget == null)
|
||||
return;
|
||||
|
||||
var tilemap = brushTarget.GetComponent<Tilemap>();
|
||||
if (tilemap == null)
|
||||
return;
|
||||
|
||||
Vector3Int min = position - pivot;
|
||||
BoundsInt bounds = new BoundsInt(min, size);
|
||||
foreach (Vector3Int location in bounds.allPositionsWithin)
|
||||
{
|
||||
var randomTile = randomTiles[(int) (randomTiles.Length * UnityEngine.Random.value)];
|
||||
tilemap.SetTile(location, randomTile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
base.Paint(grid, brushTarget, position);
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Create/Random Brush")]
|
||||
public static void CreateBrush()
|
||||
{
|
||||
string path = EditorUtility.SaveFilePanelInProject("Save Random Brush", "New Random Brush", "asset", "Save Random Brush", "Assets");
|
||||
|
||||
if (path == "")
|
||||
return;
|
||||
|
||||
AssetDatabase.CreateAsset(ScriptableObject.CreateInstance<RandomBrush>(), path);
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(RandomBrush))]
|
||||
public class RandomBrushEditor : UnityEditor.Tilemaps.GridBrushEditor
|
||||
{
|
||||
private RandomBrush randomBrush { get { return target as RandomBrush; } }
|
||||
private GameObject lastBrushTarget;
|
||||
|
||||
public override void PaintPreview(GridLayout grid, GameObject brushTarget, Vector3Int position)
|
||||
{
|
||||
if (randomBrush.randomTiles != null && randomBrush.randomTiles.Length > 0)
|
||||
{
|
||||
base.PaintPreview(grid, null, position);
|
||||
|
||||
if (brushTarget == null)
|
||||
return;
|
||||
|
||||
var tilemap = brushTarget.GetComponent<Tilemap>();
|
||||
if (tilemap == null)
|
||||
return;
|
||||
|
||||
Vector3Int min = position - randomBrush.pivot;
|
||||
BoundsInt bounds = new BoundsInt(min, randomBrush.size);
|
||||
foreach (Vector3Int location in bounds.allPositionsWithin)
|
||||
{
|
||||
var randomTile = randomBrush.randomTiles[(int) (randomBrush.randomTiles.Length * UnityEngine.Random.value)];
|
||||
tilemap.SetEditorPreviewTile(location, randomTile);
|
||||
}
|
||||
|
||||
lastBrushTarget = brushTarget;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.PaintPreview(grid, brushTarget, position);
|
||||
}
|
||||
}
|
||||
|
||||
public override void ClearPreview()
|
||||
{
|
||||
if (lastBrushTarget != null)
|
||||
{
|
||||
var tilemap = lastBrushTarget.GetComponent<Tilemap>();
|
||||
if (tilemap == null)
|
||||
return;
|
||||
|
||||
tilemap.ClearAllEditorPreviewTiles();
|
||||
|
||||
lastBrushTarget = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.ClearPreview();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnPaintInspectorGUI()
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
int count = EditorGUILayout.IntField("Number of Tiles", randomBrush.randomTiles != null ? randomBrush.randomTiles.Length : 0);
|
||||
if (count < 0)
|
||||
count = 0;
|
||||
if (randomBrush.randomTiles == null || randomBrush.randomTiles.Length != count)
|
||||
{
|
||||
Array.Resize<TileBase>(ref randomBrush.randomTiles, count);
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
EditorGUILayout.LabelField("Place random tiles.");
|
||||
EditorGUILayout.Space();
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
randomBrush.randomTiles[i] = (TileBase) EditorGUILayout.ObjectField("Tile " + (i+1), randomBrush.randomTiles[i], typeof(TileBase), false, null);
|
||||
}
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
EditorUtility.SetDirty(randomBrush);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d80edd6caba93514eb01722041fe50b4
|
||||
timeCreated: 1499223220
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/Brushes/Tint Brush Smooth.meta
Normal file
10
Assets/Scripts/UI/Tilemap/Brushes/Tint Brush Smooth.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 73ffdc5b54c50214e9899760b98f5754
|
||||
folderAsset: yes
|
||||
timeCreated: 1502798557
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3d5759c37f6ead941b87383dcb19bff3
|
||||
folderAsset: yes
|
||||
timeCreated: 1502798569
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7402f20de7e8fc34c9cfcbc965122710
|
||||
folderAsset: yes
|
||||
timeCreated: 1502800377
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Tilemaps;
|
||||
|
||||
namespace UnityEditor
|
||||
{
|
||||
[CustomGridBrush(false, false, false, "Tint Brush (Smooth)")]
|
||||
public class TintBrushSmooth : GridBrushBase
|
||||
{
|
||||
private TintTextureGenerator generator
|
||||
{
|
||||
get
|
||||
{
|
||||
TintTextureGenerator generator = FindObjectOfType<TintTextureGenerator>();
|
||||
if (generator == null)
|
||||
{
|
||||
// Note: Code assumes only one grid in scene
|
||||
Grid grid = FindObjectOfType<Grid>();
|
||||
if (grid != null)
|
||||
{
|
||||
generator = grid.gameObject.AddComponent<TintTextureGenerator>();
|
||||
}
|
||||
}
|
||||
return generator;
|
||||
}
|
||||
}
|
||||
|
||||
public Color m_Color = Color.white;
|
||||
|
||||
public override void Paint(GridLayout grid, GameObject brushTarget, Vector3Int position)
|
||||
{
|
||||
// Do not allow editing palettes
|
||||
if (brushTarget.layer == 31)
|
||||
return;
|
||||
|
||||
TintTextureGenerator generator = GetGenerator(grid);
|
||||
if (generator != null)
|
||||
{
|
||||
generator.SetColor(grid as Grid, position, m_Color);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Erase(GridLayout grid, GameObject brushTarget, Vector3Int position)
|
||||
{
|
||||
// Do not allow editing palettes
|
||||
if (brushTarget.layer == 31)
|
||||
return;
|
||||
|
||||
TintTextureGenerator generator = GetGenerator(grid);
|
||||
if (generator != null)
|
||||
{
|
||||
generator.SetColor(grid as Grid, position, Color.white);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Pick(GridLayout grid, GameObject brushTarget, BoundsInt position, Vector3Int pivot)
|
||||
{
|
||||
// Do not allow editing palettes
|
||||
if (brushTarget.layer == 31)
|
||||
return;
|
||||
|
||||
TintTextureGenerator generator = GetGenerator(grid);
|
||||
if (generator != null)
|
||||
{
|
||||
m_Color = generator.GetColor(grid as Grid, position.min);
|
||||
}
|
||||
}
|
||||
|
||||
private TintTextureGenerator GetGenerator(GridLayout grid)
|
||||
{
|
||||
TintTextureGenerator generator = FindObjectOfType<TintTextureGenerator>();
|
||||
if (generator == null)
|
||||
{
|
||||
if (grid != null)
|
||||
{
|
||||
generator = grid.gameObject.AddComponent<TintTextureGenerator>();
|
||||
}
|
||||
}
|
||||
return generator;
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(TintBrushSmooth))]
|
||||
public class TintBrushSmoothEditor : UnityEditor.Tilemaps.GridBrushEditorBase
|
||||
{
|
||||
public override GameObject[] validTargets
|
||||
{
|
||||
get
|
||||
{
|
||||
return GameObject.FindObjectsOfType<Tilemap>().Select(x => x.gameObject).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnPaintInspectorGUI()
|
||||
{
|
||||
base.OnPaintInspectorGUI();
|
||||
GUILayout.Label("Note: Tilemap needs to use TintedTilemap.shader!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ed363ce3b4856fa408111529bc784318
|
||||
timeCreated: 1502800385
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.Tilemaps;
|
||||
|
||||
[ExecuteInEditMode]
|
||||
public class TintTextureGenerator : MonoBehaviour
|
||||
{
|
||||
public int k_TintMapSize = 256;
|
||||
|
||||
private Texture2D m_TintTexture;
|
||||
|
||||
private Texture2D tintTexture
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_TintTexture == null)
|
||||
{
|
||||
m_TintTexture = new Texture2D(k_TintMapSize, k_TintMapSize, TextureFormat.ARGB32, false);
|
||||
m_TintTexture.hideFlags = HideFlags.HideAndDontSave;
|
||||
m_TintTexture.wrapMode = TextureWrapMode.Clamp;
|
||||
m_TintTexture.filterMode = FilterMode.Bilinear;
|
||||
RefreshGlobalShaderValues();
|
||||
}
|
||||
|
||||
return m_TintTexture;
|
||||
}
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
Refresh(GetComponent<Grid>());
|
||||
}
|
||||
|
||||
public void Refresh(Grid grid)
|
||||
{
|
||||
if (grid == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var w = tintTexture.width;
|
||||
var h = tintTexture.height;
|
||||
for (var y = 0; y < h; y++)
|
||||
for (var x = 0; x < w; x++)
|
||||
{
|
||||
var world = TextureToWorld(new Vector3Int(x, y, 0));
|
||||
tintTexture.SetPixel(x, y, GetGridInformation(grid).GetPositionProperty(world, "Tint", Color.white));
|
||||
}
|
||||
|
||||
tintTexture.Apply();
|
||||
}
|
||||
|
||||
public void Refresh(Grid grid, Vector3Int position)
|
||||
{
|
||||
if (grid == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshGlobalShaderValues();
|
||||
var texPosition = WorldToTexture(position);
|
||||
tintTexture.SetPixel(texPosition.x, texPosition.y, GetGridInformation(grid).GetPositionProperty(position, "Tint", Color.white));
|
||||
tintTexture.Apply();
|
||||
}
|
||||
|
||||
public Color GetColor(Grid grid, Vector3Int position)
|
||||
{
|
||||
if (grid == null)
|
||||
{
|
||||
return Color.white;
|
||||
}
|
||||
|
||||
return GetGridInformation(grid).GetPositionProperty(position, "Tint", Color.white);
|
||||
}
|
||||
|
||||
public void SetColor(Grid grid, Vector3Int position, Color color)
|
||||
{
|
||||
if (grid == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GetGridInformation(grid).SetPositionProperty(position, "Tint", color);
|
||||
Refresh(grid, position);
|
||||
}
|
||||
|
||||
private Vector3Int WorldToTexture(Vector3Int world)
|
||||
{
|
||||
return new Vector3Int(world.x + tintTexture.width / 2, world.y + tintTexture.height / 2, 0);
|
||||
}
|
||||
|
||||
private Vector3Int TextureToWorld(Vector3Int texpos)
|
||||
{
|
||||
return new Vector3Int(texpos.x - tintTexture.width / 2, texpos.y - tintTexture.height / 2, 0);
|
||||
}
|
||||
|
||||
private GridInformation GetGridInformation(Grid grid)
|
||||
{
|
||||
var gridInformation = grid.GetComponent<GridInformation>();
|
||||
|
||||
if (gridInformation == null)
|
||||
{
|
||||
gridInformation = grid.gameObject.AddComponent<GridInformation>();
|
||||
}
|
||||
|
||||
return gridInformation;
|
||||
}
|
||||
|
||||
private void RefreshGlobalShaderValues()
|
||||
{
|
||||
Shader.SetGlobalTexture("_TintMap", m_TintTexture);
|
||||
Shader.SetGlobalFloat("_TintMapSize", k_TintMapSize);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b41bf0cc11b1c8f419f96e8eb0adea40
|
||||
timeCreated: 1502798706
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f9a74a0ba597dbd4ebbdc09df032a31c
|
||||
folderAsset: yes
|
||||
timeCreated: 1502798946
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
Shader "Custom/TintedTilemap"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
[PerRendererData]_MainTex ("Albedo (RGB)", 2D) = "white" {}
|
||||
}
|
||||
|
||||
SubShader
|
||||
{
|
||||
Tags { "Queue"="Transparent" "Render"="Transparent" "IgnoreProjector"="True"}
|
||||
LOD 200
|
||||
|
||||
ZWrite Off
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
|
||||
Pass{
|
||||
CGPROGRAM
|
||||
|
||||
#pragma target 3.0
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
struct appdata {
|
||||
float4 vertex : POSITION;
|
||||
float4 texcoord : TEXCOORD0;
|
||||
};
|
||||
|
||||
sampler2D _MainTex;
|
||||
sampler2D _TintMap;
|
||||
float _TintMapSize;
|
||||
|
||||
struct v2f {
|
||||
float4 vertex : SV_POSITION;
|
||||
float4 uv : TEXCOORD0;
|
||||
float3 worldPos : float3;
|
||||
};
|
||||
|
||||
v2f vert(appdata v) {
|
||||
v2f o;
|
||||
|
||||
o.worldPos = mul (unity_ObjectToWorld, v.vertex);
|
||||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||
o.uv = float4(v.texcoord.xy, 0, 0);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
fixed4 frag(v2f i) : SV_Target {
|
||||
fixed4 col = tex2D (_MainTex, i.uv);
|
||||
fixed4 tint = tex2D(_TintMap, (i.worldPos.xy / _TintMapSize) + .5);
|
||||
return tint * col;
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
FallBack "Diffuse"
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9fcc3b710e7f7ae44bcf65125a08d5ef
|
||||
timeCreated: 1502805334
|
||||
licenseType: Pro
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/Brushes/Tint Brush.meta
Normal file
10
Assets/Scripts/UI/Tilemap/Brushes/Tint Brush.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 91dd673b6b5d18845b756aedc65463ad
|
||||
folderAsset: yes
|
||||
timeCreated: 1502200654
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/Brushes/Tint Brush/Scripts.meta
Normal file
10
Assets/Scripts/UI/Tilemap/Brushes/Tint Brush/Scripts.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0da715375d333a8418105408e081f130
|
||||
folderAsset: yes
|
||||
timeCreated: 1502200675
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 27c281d5970a0fd49bfebd8119dc790a
|
||||
folderAsset: yes
|
||||
timeCreated: 1502200680
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Tilemaps;
|
||||
|
||||
namespace UnityEditor
|
||||
{
|
||||
[CustomGridBrush(false, false, false, "Tint Brush")]
|
||||
public class TintBrush : GridBrushBase
|
||||
{
|
||||
public Color m_Color = Color.white;
|
||||
|
||||
public override void Paint(GridLayout grid, GameObject brushTarget, Vector3Int position)
|
||||
{
|
||||
// Do not allow editing palettes
|
||||
if (brushTarget.layer == 31)
|
||||
return;
|
||||
|
||||
Tilemap tilemap = brushTarget.GetComponent<Tilemap>();
|
||||
if (tilemap != null)
|
||||
{
|
||||
SetColor(tilemap, position, m_Color);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Erase(GridLayout grid, GameObject brushTarget, Vector3Int position)
|
||||
{
|
||||
// Do not allow editing palettes
|
||||
if (brushTarget.layer == 31)
|
||||
return;
|
||||
|
||||
Tilemap tilemap = brushTarget.GetComponent<Tilemap>();
|
||||
if (tilemap != null)
|
||||
{
|
||||
SetColor(tilemap, position, Color.white);
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetColor(Tilemap tilemap, Vector3Int position, Color color)
|
||||
{
|
||||
TileBase tile = tilemap.GetTile(position);
|
||||
if (tile != null)
|
||||
{
|
||||
if ((tilemap.GetTileFlags(position) & TileFlags.LockColor) != 0)
|
||||
{
|
||||
if (tile is Tile)
|
||||
{
|
||||
Debug.LogWarning("Tint brush cancelled, because Tile (" + tile.name + ") has TileFlags.LockColor set. Unlock it from the Tile asset debug inspector.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("Tint brush cancelled. because Tile (" + tile.name + ") has TileFlags.LockColor set. Unset it in GetTileData().");
|
||||
}
|
||||
}
|
||||
|
||||
tilemap.SetColor(position, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[CustomEditor(typeof(TintBrush))]
|
||||
public class TintBrushEditor : UnityEditor.Tilemaps.GridBrushEditorBase
|
||||
{
|
||||
public override GameObject[] validTargets
|
||||
{
|
||||
get
|
||||
{
|
||||
return GameObject.FindObjectsOfType<Tilemap>().Select(x => x.gameObject).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5461c6f43c33cae4e8367042630017f7
|
||||
timeCreated: 1502200727
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/GridInformation.meta
Normal file
10
Assets/Scripts/UI/Tilemap/GridInformation.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c93545baa8c686a46a0ec319b747d53f
|
||||
folderAsset: yes
|
||||
timeCreated: 1501816804
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/GridInformation/Scripts.meta
Normal file
10
Assets/Scripts/UI/Tilemap/GridInformation/Scripts.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fa5c106bc9eac9844897d7fea5f8328c
|
||||
folderAsset: yes
|
||||
timeCreated: 1499412046
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,350 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace UnityEngine.Tilemaps
|
||||
{
|
||||
[Serializable]
|
||||
internal enum GridInformationType { Integer, String, Float, Double, UnityObject, Color }
|
||||
|
||||
[Serializable, AddComponentMenu("Tilemap/Grid Information")]
|
||||
public class GridInformation : MonoBehaviour, ISerializationCallbackReceiver
|
||||
{
|
||||
[SerializeField, HideInInspector] private List<GridInformationKey> m_PositionColorKeys = new List<GridInformationKey>();
|
||||
|
||||
[SerializeField, HideInInspector] private List<Color> m_PositionColorValues = new List<Color>();
|
||||
|
||||
[SerializeField, HideInInspector] private List<GridInformationKey> m_PositionDoubleKeys = new List<GridInformationKey>();
|
||||
|
||||
[SerializeField, HideInInspector] private List<double> m_PositionDoubleValues = new List<double>();
|
||||
|
||||
[SerializeField, HideInInspector] private List<GridInformationKey> m_PositionFloatKeys = new List<GridInformationKey>();
|
||||
|
||||
[SerializeField, HideInInspector] private List<float> m_PositionFloatValues = new List<float>();
|
||||
|
||||
[SerializeField, HideInInspector] private List<GridInformationKey> m_PositionIntKeys = new List<GridInformationKey>();
|
||||
|
||||
[SerializeField, HideInInspector] private List<int> m_PositionIntValues = new List<int>();
|
||||
|
||||
[SerializeField, HideInInspector] private List<GridInformationKey> m_PositionObjectKeys = new List<GridInformationKey>();
|
||||
|
||||
[SerializeField, HideInInspector] private List<Object> m_PositionObjectValues = new List<Object>();
|
||||
|
||||
[SerializeField, HideInInspector] private List<GridInformationKey> m_PositionStringKeys = new List<GridInformationKey>();
|
||||
|
||||
[SerializeField, HideInInspector] private List<string> m_PositionStringValues = new List<string>();
|
||||
|
||||
internal Dictionary<GridInformationKey, GridInformationValue> PositionProperties { get; } =
|
||||
new Dictionary<GridInformationKey, GridInformationValue>();
|
||||
|
||||
public virtual void Reset()
|
||||
{
|
||||
PositionProperties.Clear();
|
||||
}
|
||||
|
||||
void ISerializationCallbackReceiver.OnBeforeSerialize()
|
||||
{
|
||||
var grid = GetComponentInParent<Grid>();
|
||||
if (grid == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_PositionIntKeys.Clear();
|
||||
m_PositionIntValues.Clear();
|
||||
m_PositionStringKeys.Clear();
|
||||
m_PositionStringValues.Clear();
|
||||
m_PositionFloatKeys.Clear();
|
||||
m_PositionFloatValues.Clear();
|
||||
m_PositionDoubleKeys.Clear();
|
||||
m_PositionDoubleValues.Clear();
|
||||
m_PositionObjectKeys.Clear();
|
||||
m_PositionObjectValues.Clear();
|
||||
m_PositionColorKeys.Clear();
|
||||
m_PositionColorValues.Clear();
|
||||
|
||||
foreach (var kvp in PositionProperties)
|
||||
{
|
||||
switch (kvp.Value.type)
|
||||
{
|
||||
case GridInformationType.Integer:
|
||||
m_PositionIntKeys.Add(kvp.Key);
|
||||
m_PositionIntValues.Add((int)kvp.Value.data);
|
||||
break;
|
||||
|
||||
case GridInformationType.String:
|
||||
m_PositionStringKeys.Add(kvp.Key);
|
||||
m_PositionStringValues.Add(kvp.Value.data as string);
|
||||
break;
|
||||
|
||||
case GridInformationType.Float:
|
||||
m_PositionFloatKeys.Add(kvp.Key);
|
||||
m_PositionFloatValues.Add((float)kvp.Value.data);
|
||||
break;
|
||||
|
||||
case GridInformationType.Double:
|
||||
m_PositionDoubleKeys.Add(kvp.Key);
|
||||
m_PositionDoubleValues.Add((double)kvp.Value.data);
|
||||
break;
|
||||
|
||||
case GridInformationType.Color:
|
||||
m_PositionColorKeys.Add(kvp.Key);
|
||||
m_PositionColorValues.Add((Color)kvp.Value.data);
|
||||
break;
|
||||
|
||||
default:
|
||||
m_PositionObjectKeys.Add(kvp.Key);
|
||||
m_PositionObjectValues.Add(kvp.Value.data as Object);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ISerializationCallbackReceiver.OnAfterDeserialize()
|
||||
{
|
||||
PositionProperties.Clear();
|
||||
for (var i = 0; i != Math.Min(m_PositionIntKeys.Count, m_PositionIntValues.Count); i++)
|
||||
{
|
||||
GridInformationValue positionValue;
|
||||
positionValue.type = GridInformationType.Integer;
|
||||
positionValue.data = m_PositionIntValues[i];
|
||||
PositionProperties.Add(m_PositionIntKeys[i], positionValue);
|
||||
}
|
||||
|
||||
for (var i = 0; i != Math.Min(m_PositionStringKeys.Count, m_PositionStringValues.Count); i++)
|
||||
{
|
||||
GridInformationValue positionValue;
|
||||
positionValue.type = GridInformationType.String;
|
||||
positionValue.data = m_PositionStringValues[i];
|
||||
PositionProperties.Add(m_PositionStringKeys[i], positionValue);
|
||||
}
|
||||
|
||||
for (var i = 0; i != Math.Min(m_PositionFloatKeys.Count, m_PositionFloatValues.Count); i++)
|
||||
{
|
||||
GridInformationValue positionValue;
|
||||
positionValue.type = GridInformationType.Float;
|
||||
positionValue.data = m_PositionFloatValues[i];
|
||||
PositionProperties.Add(m_PositionFloatKeys[i], positionValue);
|
||||
}
|
||||
|
||||
for (var i = 0; i != Math.Min(m_PositionDoubleKeys.Count, m_PositionDoubleValues.Count); i++)
|
||||
{
|
||||
GridInformationValue positionValue;
|
||||
positionValue.type = GridInformationType.Double;
|
||||
positionValue.data = m_PositionDoubleValues[i];
|
||||
PositionProperties.Add(m_PositionDoubleKeys[i], positionValue);
|
||||
}
|
||||
|
||||
for (var i = 0; i != Math.Min(m_PositionObjectKeys.Count, m_PositionObjectValues.Count); i++)
|
||||
{
|
||||
GridInformationValue positionValue;
|
||||
positionValue.type = GridInformationType.UnityObject;
|
||||
positionValue.data = m_PositionObjectValues[i];
|
||||
PositionProperties.Add(m_PositionObjectKeys[i], positionValue);
|
||||
}
|
||||
|
||||
for (var i = 0; i != Math.Min(m_PositionColorKeys.Count, m_PositionColorValues.Count); i++)
|
||||
{
|
||||
GridInformationValue positionValue;
|
||||
positionValue.type = GridInformationType.Color;
|
||||
positionValue.data = m_PositionColorValues[i];
|
||||
PositionProperties.Add(m_PositionColorKeys[i], positionValue);
|
||||
}
|
||||
}
|
||||
|
||||
public bool SetPositionProperty<T>(Vector3Int position, string name, T positionProperty)
|
||||
{
|
||||
throw new NotImplementedException("Storing this type is not accepted in GridInformation");
|
||||
}
|
||||
|
||||
public bool SetPositionProperty(Vector3Int position, string name, int positionProperty)
|
||||
{
|
||||
return SetPositionProperty(position, name, GridInformationType.Integer, positionProperty);
|
||||
}
|
||||
|
||||
public bool SetPositionProperty(Vector3Int position, string name, string positionProperty)
|
||||
{
|
||||
return SetPositionProperty(position, name, GridInformationType.String, positionProperty);
|
||||
}
|
||||
|
||||
public bool SetPositionProperty(Vector3Int position, string name, float positionProperty)
|
||||
{
|
||||
return SetPositionProperty(position, name, GridInformationType.Float, positionProperty);
|
||||
}
|
||||
|
||||
public bool SetPositionProperty(Vector3Int position, string name, double positionProperty)
|
||||
{
|
||||
return SetPositionProperty(position, name, GridInformationType.Double, positionProperty);
|
||||
}
|
||||
|
||||
public bool SetPositionProperty(Vector3Int position, string name, Object positionProperty)
|
||||
{
|
||||
return SetPositionProperty(position, name, GridInformationType.UnityObject, positionProperty);
|
||||
}
|
||||
|
||||
public bool SetPositionProperty(Vector3Int position, string name, Color positionProperty)
|
||||
{
|
||||
return SetPositionProperty(position, name, GridInformationType.Color, positionProperty);
|
||||
}
|
||||
|
||||
private bool SetPositionProperty(Vector3Int position, string name, GridInformationType dataType, object positionProperty)
|
||||
{
|
||||
var grid = GetComponentInParent<Grid>();
|
||||
if (grid != null && positionProperty != null)
|
||||
{
|
||||
GridInformationKey positionKey;
|
||||
positionKey.position = position;
|
||||
positionKey.name = name;
|
||||
|
||||
GridInformationValue positionValue;
|
||||
positionValue.type = dataType;
|
||||
positionValue.data = positionProperty;
|
||||
|
||||
PositionProperties[positionKey] = positionValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public T GetPositionProperty<T>(Vector3Int position, string name, T defaultValue) where T : Object
|
||||
{
|
||||
GridInformationKey positionKey;
|
||||
positionKey.position = position;
|
||||
positionKey.name = name;
|
||||
|
||||
GridInformationValue positionValue;
|
||||
if (PositionProperties.TryGetValue(positionKey, out positionValue))
|
||||
{
|
||||
if (positionValue.type != GridInformationType.UnityObject)
|
||||
{
|
||||
throw new InvalidCastException("Value stored in GridInformation is not of the right type");
|
||||
}
|
||||
return positionValue.data as T;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public int GetPositionProperty(Vector3Int position, string name, int defaultValue)
|
||||
{
|
||||
GridInformationKey positionKey;
|
||||
positionKey.position = position;
|
||||
positionKey.name = name;
|
||||
|
||||
GridInformationValue positionValue;
|
||||
if (PositionProperties.TryGetValue(positionKey, out positionValue))
|
||||
{
|
||||
if (positionValue.type != GridInformationType.Integer)
|
||||
{
|
||||
throw new InvalidCastException("Value stored in GridInformation is not of the right type");
|
||||
}
|
||||
return (int)positionValue.data;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public string GetPositionProperty(Vector3Int position, string name, string defaultValue)
|
||||
{
|
||||
GridInformationKey positionKey;
|
||||
positionKey.position = position;
|
||||
positionKey.name = name;
|
||||
|
||||
GridInformationValue positionValue;
|
||||
if (PositionProperties.TryGetValue(positionKey, out positionValue))
|
||||
{
|
||||
if (positionValue.type != GridInformationType.String)
|
||||
{
|
||||
throw new InvalidCastException("Value stored in GridInformation is not of the right type");
|
||||
}
|
||||
return (string)positionValue.data;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public float GetPositionProperty(Vector3Int position, string name, float defaultValue)
|
||||
{
|
||||
GridInformationKey positionKey;
|
||||
positionKey.position = position;
|
||||
positionKey.name = name;
|
||||
|
||||
GridInformationValue positionValue;
|
||||
if (PositionProperties.TryGetValue(positionKey, out positionValue))
|
||||
{
|
||||
if (positionValue.type != GridInformationType.Float)
|
||||
{
|
||||
throw new InvalidCastException("Value stored in GridInformation is not of the right type");
|
||||
}
|
||||
return (float)positionValue.data;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public double GetPositionProperty(Vector3Int position, string name, double defaultValue)
|
||||
{
|
||||
GridInformationKey positionKey;
|
||||
positionKey.position = position;
|
||||
positionKey.name = name;
|
||||
|
||||
GridInformationValue positionValue;
|
||||
if (PositionProperties.TryGetValue(positionKey, out positionValue))
|
||||
{
|
||||
if (positionValue.type != GridInformationType.Double)
|
||||
{
|
||||
throw new InvalidCastException("Value stored in GridInformation is not of the right type");
|
||||
}
|
||||
return (double)positionValue.data;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public Color GetPositionProperty(Vector3Int position, string name, Color defaultValue)
|
||||
{
|
||||
GridInformationKey positionKey;
|
||||
positionKey.position = position;
|
||||
positionKey.name = name;
|
||||
|
||||
GridInformationValue positionValue;
|
||||
if (PositionProperties.TryGetValue(positionKey, out positionValue))
|
||||
{
|
||||
if (positionValue.type != GridInformationType.Color)
|
||||
{
|
||||
throw new InvalidCastException("Value stored in GridInformation is not of the right type");
|
||||
}
|
||||
return (Color)positionValue.data;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public bool ErasePositionProperty(Vector3Int position, string name)
|
||||
{
|
||||
GridInformationKey positionKey;
|
||||
positionKey.position = position;
|
||||
positionKey.name = name;
|
||||
return PositionProperties.Remove(positionKey);
|
||||
}
|
||||
|
||||
public Vector3Int[] GetAllPositions(string propertyName)
|
||||
{
|
||||
return PositionProperties.Keys.ToList().FindAll(x => x.name == propertyName).Select(x => x.position).ToArray();
|
||||
}
|
||||
|
||||
internal struct GridInformationValue
|
||||
{
|
||||
public GridInformationType type;
|
||||
public object data;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal struct GridInformationKey
|
||||
{
|
||||
public Vector3Int position;
|
||||
public string name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e7bb9acb2cffc5f45abddc238a0ad9b0
|
||||
timeCreated: 1501815409
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/Tiles.meta
Normal file
10
Assets/Scripts/UI/Tilemap/Tiles.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a4b96e08a92a0de42b0c2fd3c56516b4
|
||||
folderAsset: yes
|
||||
timeCreated: 1499149591
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/Tiles/Animated Tile.meta
Normal file
10
Assets/Scripts/UI/Tilemap/Tiles/Animated Tile.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 33e8a22612607064dbfaa9d21d1836e8
|
||||
folderAsset: yes
|
||||
timeCreated: 1499149327
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/Tiles/Animated Tile/Scripts.meta
Normal file
10
Assets/Scripts/UI/Tilemap/Tiles/Animated Tile/Scripts.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d8f0a7d912b6f424aa0e09f8597dd2df
|
||||
folderAsset: yes
|
||||
timeCreated: 1499149343
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
using System;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
|
||||
#endif
|
||||
|
||||
namespace UnityEngine.Tilemaps
|
||||
{
|
||||
[Serializable]
|
||||
public class AnimatedTile : TileBase
|
||||
{
|
||||
public Sprite[] m_AnimatedSprites;
|
||||
public float m_AnimationStartTime;
|
||||
public float m_MaxSpeed = 1f;
|
||||
public float m_MinSpeed = 1f;
|
||||
public Tile.ColliderType m_TileColliderType;
|
||||
|
||||
public override void GetTileData(Vector3Int location, ITilemap tileMap, ref TileData tileData)
|
||||
{
|
||||
tileData.transform = Matrix4x4.identity;
|
||||
tileData.color = Color.white;
|
||||
if (m_AnimatedSprites != null && m_AnimatedSprites.Length > 0)
|
||||
{
|
||||
tileData.sprite = m_AnimatedSprites[m_AnimatedSprites.Length - 1];
|
||||
tileData.colliderType = m_TileColliderType;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool GetTileAnimationData(Vector3Int location, ITilemap tileMap, ref TileAnimationData tileAnimationData)
|
||||
{
|
||||
if (m_AnimatedSprites.Length > 0)
|
||||
{
|
||||
tileAnimationData.animatedSprites = m_AnimatedSprites;
|
||||
tileAnimationData.animationSpeed = Random.Range(m_MinSpeed, m_MaxSpeed);
|
||||
tileAnimationData.animationStartTime = m_AnimationStartTime;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[MenuItem("Assets/Create/Animated Tile")]
|
||||
public static void CreateAnimatedTile()
|
||||
{
|
||||
var path = EditorUtility.SaveFilePanelInProject("Save Animated Tile", "New Animated Tile", "asset", "Save Animated Tile", "Assets");
|
||||
if (path == "")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AssetDatabase.CreateAsset(CreateInstance<AnimatedTile>(), path);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[CustomEditor(typeof(AnimatedTile))]
|
||||
public class AnimatedTileEditor : Editor
|
||||
{
|
||||
private AnimatedTile tile => target as AnimatedTile;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
var count = EditorGUILayout.DelayedIntField(
|
||||
"Number of Animated Sprites",
|
||||
tile.m_AnimatedSprites != null ? tile.m_AnimatedSprites.Length : 0);
|
||||
if (count < 0)
|
||||
{
|
||||
count = 0;
|
||||
}
|
||||
|
||||
if (tile.m_AnimatedSprites == null || tile.m_AnimatedSprites.Length != count)
|
||||
{
|
||||
Array.Resize(ref tile.m_AnimatedSprites, count);
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField("Place sprites shown based on the order of animation.");
|
||||
EditorGUILayout.Space();
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
tile.m_AnimatedSprites[i] = (Sprite)EditorGUILayout.ObjectField(
|
||||
"Sprite " + (i + 1),
|
||||
tile.m_AnimatedSprites[i],
|
||||
typeof(Sprite),
|
||||
false,
|
||||
null);
|
||||
}
|
||||
|
||||
var minSpeed = EditorGUILayout.FloatField("Minimum Speed", tile.m_MinSpeed);
|
||||
var maxSpeed = EditorGUILayout.FloatField("Maximum Speed", tile.m_MaxSpeed);
|
||||
if (minSpeed < 0.0f)
|
||||
{
|
||||
minSpeed = 0.0f;
|
||||
}
|
||||
|
||||
if (maxSpeed < 0.0f)
|
||||
{
|
||||
maxSpeed = 0.0f;
|
||||
}
|
||||
|
||||
if (maxSpeed < minSpeed)
|
||||
{
|
||||
maxSpeed = minSpeed;
|
||||
}
|
||||
|
||||
tile.m_MinSpeed = minSpeed;
|
||||
tile.m_MaxSpeed = maxSpeed;
|
||||
|
||||
tile.m_AnimationStartTime = EditorGUILayout.FloatField("Start Time", tile.m_AnimationStartTime);
|
||||
tile.m_TileColliderType = (Tile.ColliderType)EditorGUILayout.EnumPopup("Collider Type", tile.m_TileColliderType);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
EditorUtility.SetDirty(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 13b75c95f34a00d4e8c04f76b73312e6
|
||||
timeCreated: 1464531813
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/Tiles/Pipeline Tile.meta
Normal file
10
Assets/Scripts/UI/Tilemap/Tiles/Pipeline Tile.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: af0bc89550613a14fa0feadd363358e6
|
||||
folderAsset: yes
|
||||
timeCreated: 1499149527
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/Tiles/Pipeline Tile/Scripts.meta
Normal file
10
Assets/Scripts/UI/Tilemap/Tiles/Pipeline Tile/Scripts.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 64fa95bf1baeb5f4497bd5048a284208
|
||||
folderAsset: yes
|
||||
timeCreated: 1499146919
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
using System;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
|
||||
#endif
|
||||
|
||||
namespace UnityEngine.Tilemaps
|
||||
{
|
||||
[Serializable]
|
||||
public class PipelineTile : TileBase
|
||||
{
|
||||
[SerializeField] public Sprite[] m_Sprites;
|
||||
|
||||
public override void RefreshTile(Vector3Int location, ITilemap tileMap)
|
||||
{
|
||||
for (var yd = -1; yd <= 1; yd++)
|
||||
for (var xd = -1; xd <= 1; xd++)
|
||||
{
|
||||
var position = new Vector3Int(location.x + xd, location.y + yd, location.z);
|
||||
if (TileValue(tileMap, position))
|
||||
{
|
||||
tileMap.RefreshTile(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void GetTileData(Vector3Int location, ITilemap tileMap, ref TileData tileData)
|
||||
{
|
||||
UpdateTile(location, tileMap, ref tileData);
|
||||
}
|
||||
|
||||
private void UpdateTile(Vector3Int location, ITilemap tileMap, ref TileData tileData)
|
||||
{
|
||||
tileData.transform = Matrix4x4.identity;
|
||||
tileData.color = Color.white;
|
||||
|
||||
var mask = TileValue(tileMap, location + new Vector3Int(0, 1, 0)) ? 1 : 0;
|
||||
mask += TileValue(tileMap, location + new Vector3Int(1, 0, 0)) ? 2 : 0;
|
||||
mask += TileValue(tileMap, location + new Vector3Int(0, -1, 0)) ? 4 : 0;
|
||||
mask += TileValue(tileMap, location + new Vector3Int(-1, 0, 0)) ? 8 : 0;
|
||||
|
||||
var index = GetIndex((byte)mask);
|
||||
if (index >= 0 && index < m_Sprites.Length && TileValue(tileMap, location))
|
||||
{
|
||||
tileData.sprite = m_Sprites[index];
|
||||
tileData.transform = GetTransform((byte)mask);
|
||||
tileData.flags = TileFlags.LockTransform | TileFlags.LockColor;
|
||||
tileData.colliderType = Tile.ColliderType.Sprite;
|
||||
}
|
||||
}
|
||||
|
||||
private bool TileValue(ITilemap tileMap, Vector3Int position)
|
||||
{
|
||||
var tile = tileMap.GetTile(position);
|
||||
return tile != null && tile == this;
|
||||
}
|
||||
|
||||
private int GetIndex(byte mask)
|
||||
{
|
||||
switch (mask)
|
||||
{
|
||||
case 0: return 0;
|
||||
|
||||
case 3:
|
||||
case 6:
|
||||
case 9:
|
||||
case 12: return 1;
|
||||
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 5:
|
||||
case 10:
|
||||
case 8: return 2;
|
||||
|
||||
case 7:
|
||||
case 11:
|
||||
case 13:
|
||||
case 14: return 3;
|
||||
|
||||
case 15: return 4;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private Matrix4x4 GetTransform(byte mask)
|
||||
{
|
||||
switch (mask)
|
||||
{
|
||||
case 9:
|
||||
case 10:
|
||||
case 7:
|
||||
case 2:
|
||||
case 8:
|
||||
return Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, -90f), Vector3.one);
|
||||
|
||||
case 3:
|
||||
case 14:
|
||||
return Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, -180f), Vector3.one);
|
||||
|
||||
case 6:
|
||||
case 13:
|
||||
return Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, -270f), Vector3.one);
|
||||
}
|
||||
|
||||
return Matrix4x4.identity;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[MenuItem("Assets/Create/Pipeline Tile")]
|
||||
public static void CreatePipelineTile()
|
||||
{
|
||||
var path = EditorUtility.SaveFilePanelInProject("Save Pipeline Tile", "New Pipeline Tile", "asset", "Save Pipeline Tile", "Assets");
|
||||
|
||||
if (path == "")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AssetDatabase.CreateAsset(CreateInstance<PipelineTile>(), path);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[CustomEditor(typeof(PipelineTile))]
|
||||
public class PipelineTileEditor : Editor
|
||||
{
|
||||
private PipelineTile tile => target as PipelineTile;
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
if (tile.m_Sprites == null || tile.m_Sprites.Length != 5)
|
||||
{
|
||||
tile.m_Sprites = new Sprite[5];
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.LabelField("Place sprites shown based on the number of tiles bordering it.");
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
tile.m_Sprites[0] = (Sprite)EditorGUILayout.ObjectField("None", tile.m_Sprites[0], typeof(Sprite), false, null);
|
||||
tile.m_Sprites[2] = (Sprite)EditorGUILayout.ObjectField("One", tile.m_Sprites[2], typeof(Sprite), false, null);
|
||||
tile.m_Sprites[1] = (Sprite)EditorGUILayout.ObjectField("Two", tile.m_Sprites[1], typeof(Sprite), false, null);
|
||||
tile.m_Sprites[3] = (Sprite)EditorGUILayout.ObjectField("Three", tile.m_Sprites[3], typeof(Sprite), false, null);
|
||||
tile.m_Sprites[4] = (Sprite)EditorGUILayout.ObjectField("Four", tile.m_Sprites[4], typeof(Sprite), false, null);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
EditorUtility.SetDirty(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 25192638efa881c469b1ac4d8cfd3f1b
|
||||
timeCreated: 1464534747
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/Tiles/Random Tile.meta
Normal file
10
Assets/Scripts/UI/Tilemap/Tiles/Random Tile.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 47f5287a949e1094191c733949de285a
|
||||
folderAsset: yes
|
||||
timeCreated: 1499150037
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/Tiles/Random Tile/Scripts.meta
Normal file
10
Assets/Scripts/UI/Tilemap/Tiles/Random Tile/Scripts.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0c3034e66d810604680654a1e667fde0
|
||||
folderAsset: yes
|
||||
timeCreated: 1499150048
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
using System;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
|
||||
#endif
|
||||
|
||||
namespace UnityEngine.Tilemaps
|
||||
{
|
||||
[Serializable]
|
||||
public class RandomTile : Tile
|
||||
{
|
||||
[SerializeField] public Sprite[] m_Sprites;
|
||||
|
||||
public override void GetTileData(Vector3Int location, ITilemap tileMap, ref TileData tileData)
|
||||
{
|
||||
base.GetTileData(location, tileMap, ref tileData);
|
||||
if (m_Sprites != null && m_Sprites.Length > 0)
|
||||
{
|
||||
long hash = location.x;
|
||||
hash = hash + 0xabcd1234 + (hash << 15);
|
||||
hash = (hash + 0x0987efab) ^ (hash >> 11);
|
||||
hash ^= location.y;
|
||||
hash = hash + 0x46ac12fd + (hash << 7);
|
||||
hash = (hash + 0xbe9730af) ^ (hash << 11);
|
||||
Random.InitState((int)hash);
|
||||
tileData.sprite = m_Sprites[(int)(m_Sprites.Length * Random.value)];
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[MenuItem("Assets/Create/Random Tile")]
|
||||
public static void CreateRandomTile()
|
||||
{
|
||||
var path = EditorUtility.SaveFilePanelInProject("Save Random Tile", "New Random Tile", "asset", "Save Random Tile", "Assets");
|
||||
|
||||
if (path == "")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AssetDatabase.CreateAsset(CreateInstance<RandomTile>(), path);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[CustomEditor(typeof(RandomTile))]
|
||||
public class RandomTileEditor : Editor
|
||||
{
|
||||
private RandomTile tile => target as RandomTile;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
var count = EditorGUILayout.DelayedIntField("Number of Sprites", tile.m_Sprites != null ? tile.m_Sprites.Length : 0);
|
||||
if (count < 0)
|
||||
{
|
||||
count = 0;
|
||||
}
|
||||
if (tile.m_Sprites == null || tile.m_Sprites.Length != count)
|
||||
{
|
||||
Array.Resize(ref tile.m_Sprites, count);
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField("Place random sprites.");
|
||||
EditorGUILayout.Space();
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
tile.m_Sprites[i] = (Sprite)EditorGUILayout.ObjectField("Sprite " + (i + 1), tile.m_Sprites[i], typeof(Sprite), false, null);
|
||||
}
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
EditorUtility.SetDirty(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 535f8e525ff367c4ba67961e201a05ed
|
||||
timeCreated: 1445235751
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Scripts/UI/Tilemap/Tiles/Rule Override Tile.meta
Normal file
8
Assets/Scripts/UI/Tilemap/Tiles/Rule Override Tile.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fbcacf945e7001e4396ca2ca8573ae6c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1e5614e4b96700843ba104987c4f190e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1263d004036ee7f42aeed98348b5e8cf
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,350 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.Tilemaps;
|
||||
using UnityEditor;
|
||||
using UnityEditorInternal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEditor
|
||||
{
|
||||
[CustomEditor(typeof(RuleOverrideTile))]
|
||||
internal class RuleOverrideTileEditor : Editor
|
||||
{
|
||||
|
||||
public RuleOverrideTile overrideTile { get { return (target as RuleOverrideTile); } }
|
||||
|
||||
private List<KeyValuePair<Sprite, Sprite>> m_Sprites;
|
||||
private List<KeyValuePair<RuleTile.TilingRule, RuleTile.TilingRule>> m_Rules;
|
||||
|
||||
ReorderableList m_SpriteList;
|
||||
ReorderableList m_RuleList;
|
||||
|
||||
private float k_DefaultElementHeight { get { return RuleTileEditor.k_DefaultElementHeight; } }
|
||||
private float k_PaddingBetweenRules { get { return RuleTileEditor.k_PaddingBetweenRules; } }
|
||||
private float k_SingleLineHeight { get { return RuleTileEditor.k_SingleLineHeight; } }
|
||||
private float k_LabelWidth { get { return RuleTileEditor.k_LabelWidth; } }
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if (m_Sprites == null)
|
||||
m_Sprites = new List<KeyValuePair<Sprite, Sprite>>();
|
||||
|
||||
if (m_Rules == null)
|
||||
m_Rules = new List<KeyValuePair<RuleTile.TilingRule, RuleTile.TilingRule>>();
|
||||
|
||||
if (m_SpriteList == null)
|
||||
{
|
||||
overrideTile.GetOverrides(m_Sprites);
|
||||
|
||||
m_SpriteList = new ReorderableList(m_Sprites, typeof(KeyValuePair<Sprite, Sprite>), false, true, false, false);
|
||||
m_SpriteList.drawHeaderCallback = DrawSpriteHeader;
|
||||
m_SpriteList.drawElementCallback = DrawSpriteElement;
|
||||
m_SpriteList.elementHeight = k_DefaultElementHeight + k_PaddingBetweenRules;
|
||||
}
|
||||
if (m_RuleList == null)
|
||||
{
|
||||
overrideTile.GetOverrides(m_Rules);
|
||||
|
||||
m_RuleList = new ReorderableList(m_Rules, typeof(KeyValuePair<RuleTile.TilingRule, RuleTile.TilingRule>), false, true, false, false);
|
||||
m_RuleList.drawHeaderCallback = DrawRuleHeader;
|
||||
m_RuleList.drawElementCallback = DrawRuleElement;
|
||||
m_RuleList.elementHeightCallback = GetRuleElementHeight;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.UpdateIfRequiredOrScript();
|
||||
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("m_Tile"));
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("m_Advanced"));
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
if (!overrideTile.m_Advanced)
|
||||
{
|
||||
using (new EditorGUI.DisabledScope(overrideTile.m_Tile == null))
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
overrideTile.GetOverrides(m_Sprites);
|
||||
|
||||
m_SpriteList.list = m_Sprites;
|
||||
m_SpriteList.DoLayoutList();
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
for (int i = 0; i < targets.Length; i++)
|
||||
{
|
||||
RuleOverrideTile tile = targets[i] as RuleOverrideTile;
|
||||
tile.ApplyOverrides(m_Sprites);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (new EditorGUI.DisabledScope(overrideTile.m_Tile == null))
|
||||
{
|
||||
overrideTile.GetOverrides(m_Rules);
|
||||
|
||||
m_RuleList.list = m_Rules;
|
||||
m_RuleList.DoLayoutList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveTile()
|
||||
{
|
||||
EditorUtility.SetDirty(target);
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
|
||||
private void DrawSpriteElement(Rect rect, int index, bool selected, bool focused)
|
||||
{
|
||||
Sprite originalSprite = m_Sprites[index].Key;
|
||||
Sprite overrideSprite = m_Sprites[index].Value;
|
||||
|
||||
rect.y += 2;
|
||||
rect.height -= k_PaddingBetweenRules;
|
||||
|
||||
rect.xMax = rect.xMax / 2.0f;
|
||||
using (new EditorGUI.DisabledScope(true))
|
||||
EditorGUI.ObjectField(new Rect(rect.xMin, rect.yMin, rect.height, rect.height), originalSprite, typeof(Sprite), false);
|
||||
rect.xMin = rect.xMax;
|
||||
rect.xMax *= 2.0f;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
overrideSprite = EditorGUI.ObjectField(new Rect(rect.xMin, rect.yMin, rect.height, rect.height), overrideSprite, typeof(Sprite), false) as Sprite;
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
m_Sprites[index] = new KeyValuePair<Sprite, Sprite>(originalSprite, overrideSprite);
|
||||
SaveTile();
|
||||
}
|
||||
}
|
||||
private void DrawSpriteHeader(Rect rect)
|
||||
{
|
||||
float xMax = rect.xMax;
|
||||
rect.xMax = rect.xMax / 2.0f;
|
||||
GUI.Label(rect, "Original", EditorStyles.label);
|
||||
rect.xMin = rect.xMax;
|
||||
rect.xMax = xMax;
|
||||
GUI.Label(rect, "Override", EditorStyles.label);
|
||||
}
|
||||
|
||||
private void DrawRuleElement(Rect rect, int index, bool selected, bool focused)
|
||||
{
|
||||
RuleTile.TilingRule originalRule = m_Rules[index].Key;
|
||||
RuleTile.TilingRule overrideRule = m_Rules[index].Value;
|
||||
|
||||
float matrixWidth = k_DefaultElementHeight;
|
||||
|
||||
float xMax = rect.xMax;
|
||||
rect.xMax = rect.xMax / 2.0f + matrixWidth - 10f;
|
||||
|
||||
if (index != overrideTile.m_Tile.m_TilingRules.Count)
|
||||
DrawOriginalRuleElement(rect, originalRule);
|
||||
else
|
||||
DrawOriginalRuleElement(rect, originalRule, true);
|
||||
|
||||
rect.xMin = rect.xMax;
|
||||
rect.xMax = xMax;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
if (index != overrideTile.m_Tile.m_TilingRules.Count)
|
||||
DrawOverrideElement(rect, originalRule);
|
||||
else
|
||||
DrawOverrideDefaultElement(rect, overrideRule);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
SaveTile();
|
||||
}
|
||||
public void DrawOriginalRuleElement(Rect rect, RuleTile.TilingRule originalRule, bool isDefault = false)
|
||||
{
|
||||
using (new EditorGUI.DisabledScope(true))
|
||||
{
|
||||
float yPos = rect.yMin + 2f;
|
||||
float height = rect.height - k_PaddingBetweenRules;
|
||||
float matrixWidth = k_DefaultElementHeight;
|
||||
|
||||
Rect inspectorRect = new Rect(rect.xMin, yPos, rect.width - matrixWidth * 2f - 20f, height);
|
||||
Rect matrixRect = new Rect(rect.xMax - matrixWidth * 2f - 10f, yPos, matrixWidth, k_DefaultElementHeight);
|
||||
Rect spriteRect = new Rect(rect.xMax - matrixWidth - 5f, yPos, matrixWidth, k_DefaultElementHeight);
|
||||
|
||||
if (!isDefault)
|
||||
RuleTileEditor.RuleInspectorOnGUI(inspectorRect, originalRule);
|
||||
else
|
||||
RuleOriginalDefaultInspectorOnGUI(inspectorRect, originalRule);
|
||||
RuleTileEditor.RuleMatrixOnGUI(matrixRect, originalRule);
|
||||
RuleTileEditor.SpriteOnGUI(spriteRect, originalRule);
|
||||
}
|
||||
}
|
||||
private void DrawOverrideElement(Rect rect, RuleTile.TilingRule originalRule)
|
||||
{
|
||||
float yPos = rect.yMin + 2f;
|
||||
float height = rect.height - k_PaddingBetweenRules;
|
||||
float matrixWidth = k_DefaultElementHeight;
|
||||
|
||||
Rect inspectorRect = new Rect(rect.xMin, yPos, rect.width - matrixWidth - 10f, height);
|
||||
Rect spriteRect = new Rect(rect.xMax - matrixWidth - 5f, yPos, matrixWidth, k_DefaultElementHeight);
|
||||
|
||||
RuleOverrideInspectorOnGUI(inspectorRect, originalRule);
|
||||
RuleTile.TilingRule overrideRule = overrideTile[originalRule];
|
||||
if (overrideRule != null)
|
||||
RuleTileEditor.SpriteOnGUI(spriteRect, overrideRule);
|
||||
}
|
||||
private void RuleOriginalDefaultInspectorOnGUI(Rect rect, RuleTile.TilingRule originalRule)
|
||||
{
|
||||
float y = rect.yMin;
|
||||
|
||||
GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Rule");
|
||||
EditorGUI.LabelField(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), "Default");
|
||||
y += k_SingleLineHeight;
|
||||
|
||||
GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Collider");
|
||||
EditorGUI.EnumPopup(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), originalRule.m_ColliderType);
|
||||
y += k_SingleLineHeight;
|
||||
}
|
||||
private void RuleOverrideInspectorOnGUI(Rect rect, RuleTile.TilingRule originalRule)
|
||||
{
|
||||
RuleTile.TilingRule overrideRule = overrideTile[originalRule];
|
||||
|
||||
float y = rect.yMin;
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Enabled");
|
||||
bool enabled = EditorGUI.Toggle(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), overrideRule != null);
|
||||
y += k_SingleLineHeight;
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
if (enabled)
|
||||
overrideTile[originalRule] = originalRule;
|
||||
else
|
||||
overrideTile[originalRule] = null;
|
||||
overrideRule = overrideTile[originalRule];
|
||||
}
|
||||
|
||||
if (overrideRule == null)
|
||||
return;
|
||||
|
||||
GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Collider");
|
||||
overrideRule.m_ColliderType = (Tile.ColliderType)EditorGUI.EnumPopup(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), overrideRule.m_ColliderType);
|
||||
y += k_SingleLineHeight;
|
||||
GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Output");
|
||||
overrideRule.m_Output = (RuleTile.TilingRule.OutputSprite)EditorGUI.EnumPopup(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), overrideRule.m_Output);
|
||||
y += k_SingleLineHeight;
|
||||
|
||||
if (overrideRule.m_Output == RuleTile.TilingRule.OutputSprite.Animation)
|
||||
{
|
||||
GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Speed");
|
||||
overrideRule.m_AnimationSpeed = EditorGUI.FloatField(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), overrideRule.m_AnimationSpeed);
|
||||
y += k_SingleLineHeight;
|
||||
}
|
||||
if (overrideRule.m_Output == RuleTile.TilingRule.OutputSprite.Random)
|
||||
{
|
||||
GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Noise");
|
||||
overrideRule.m_PerlinScale = EditorGUI.Slider(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), overrideRule.m_PerlinScale, 0.001f, 0.999f);
|
||||
y += k_SingleLineHeight;
|
||||
|
||||
GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Shuffle");
|
||||
overrideRule.m_RandomTransform = (RuleTile.TilingRule.Transform)EditorGUI.EnumPopup(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), overrideRule.m_RandomTransform);
|
||||
y += k_SingleLineHeight;
|
||||
}
|
||||
|
||||
if (overrideRule.m_Output != RuleTile.TilingRule.OutputSprite.Single)
|
||||
{
|
||||
GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Size");
|
||||
EditorGUI.BeginChangeCheck();
|
||||
int newLength = EditorGUI.DelayedIntField(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), overrideRule.m_Sprites.Length);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
Array.Resize(ref overrideRule.m_Sprites, Math.Max(newLength, 1));
|
||||
y += k_SingleLineHeight;
|
||||
|
||||
for (int i = 0; i < overrideRule.m_Sprites.Length; i++)
|
||||
{
|
||||
overrideRule.m_Sprites[i] = EditorGUI.ObjectField(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), overrideRule.m_Sprites[i], typeof(Sprite), false) as Sprite;
|
||||
y += k_SingleLineHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void DrawOverrideDefaultElement(Rect rect, RuleTile.TilingRule originalRule)
|
||||
{
|
||||
float yPos = rect.yMin + 2f;
|
||||
float height = rect.height - k_PaddingBetweenRules;
|
||||
float matrixWidth = k_DefaultElementHeight;
|
||||
|
||||
Rect inspectorRect = new Rect(rect.xMin, yPos, rect.width - matrixWidth - 10f, height);
|
||||
Rect spriteRect = new Rect(rect.xMax - matrixWidth - 5f, yPos, matrixWidth, k_DefaultElementHeight);
|
||||
|
||||
RuleOverrideDefaultInspectorOnGUI(inspectorRect, originalRule);
|
||||
if (overrideTile.m_OverrideDefault.m_Enabled)
|
||||
RuleTileEditor.SpriteOnGUI(spriteRect, overrideTile.m_OverrideDefault.m_TilingRule);
|
||||
}
|
||||
private void RuleOverrideDefaultInspectorOnGUI(Rect rect, RuleTile.TilingRule overrideRule)
|
||||
{
|
||||
float y = rect.yMin;
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Enabled");
|
||||
bool enabled = EditorGUI.Toggle(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), overrideTile.m_OverrideDefault.m_Enabled);
|
||||
y += k_SingleLineHeight;
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
overrideTile.m_OverrideDefault.m_Enabled = enabled;
|
||||
overrideTile.m_OverrideDefault.m_TilingRule = overrideTile.m_OriginalDefault;
|
||||
}
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Collider");
|
||||
overrideRule.m_ColliderType = (Tile.ColliderType)EditorGUI.EnumPopup(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), overrideRule.m_ColliderType);
|
||||
y += k_SingleLineHeight;
|
||||
}
|
||||
private void DrawRuleHeader(Rect rect)
|
||||
{
|
||||
overrideTile.Override();
|
||||
|
||||
float matrixWidth = k_DefaultElementHeight;
|
||||
|
||||
float xMax = rect.xMax;
|
||||
rect.xMax = rect.xMax / 2.0f + matrixWidth - 10f;
|
||||
GUI.Label(rect, "Original", EditorStyles.label);
|
||||
rect.xMin = rect.xMax;
|
||||
rect.xMax = xMax;
|
||||
GUI.Label(rect, "Override", EditorStyles.label);
|
||||
}
|
||||
private float GetRuleElementHeight(int index)
|
||||
{
|
||||
if (index != overrideTile.m_Tile.m_TilingRules.Count)
|
||||
{
|
||||
var overrideRule = overrideTile[overrideTile.m_Tile.m_TilingRules[index]];
|
||||
float overrideHeight = GetRuleElementHeight(overrideRule);
|
||||
float originalHeight = GetRuleElementHeight(overrideTile.m_Tile.m_TilingRules[index]);
|
||||
return Mathf.Max(overrideHeight, originalHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
var overrideRule = overrideTile.m_OverrideDefault.m_Enabled ? overrideTile.m_OverrideDefault.m_TilingRule : null;
|
||||
float overrideHeight = GetRuleElementHeight(overrideRule);
|
||||
float originalHeight = GetRuleElementHeight(new RuleTile.TilingRule());
|
||||
return Mathf.Max(overrideHeight, originalHeight);
|
||||
}
|
||||
}
|
||||
private float GetRuleElementHeight(RuleTile.TilingRule rule)
|
||||
{
|
||||
float height = k_DefaultElementHeight + k_PaddingBetweenRules;
|
||||
if (rule != null)
|
||||
{
|
||||
switch (rule.m_Output)
|
||||
{
|
||||
case RuleTile.TilingRule.OutputSprite.Random:
|
||||
height = k_DefaultElementHeight + k_SingleLineHeight * (rule.m_Sprites.Length + 3) + k_PaddingBetweenRules;
|
||||
break;
|
||||
case RuleTile.TilingRule.OutputSprite.Animation:
|
||||
height = k_DefaultElementHeight + k_SingleLineHeight * (rule.m_Sprites.Length + 2) + k_PaddingBetweenRules;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dd977390416471341b10fd1278290da0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,331 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine.Tilemaps;
|
||||
|
||||
namespace UnityEngine
|
||||
{
|
||||
[Serializable, CreateAssetMenu]
|
||||
public class RuleOverrideTile : TileBase
|
||||
{
|
||||
public bool m_Advanced;
|
||||
public OverrideTilingRule m_OverrideDefault = new OverrideTilingRule();
|
||||
public List<OverrideTilingRule> m_OverrideTilingRules = new List<OverrideTilingRule>();
|
||||
public List<TileSpritePair> m_Sprites = new List<TileSpritePair>();
|
||||
|
||||
public RuleTile m_Tile;
|
||||
|
||||
private RuleTile m_RuntimeTile;
|
||||
|
||||
public Sprite this[Sprite originalSprite]
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var spritePair in m_Sprites)
|
||||
{
|
||||
if (spritePair.m_OriginalSprite == originalSprite)
|
||||
{
|
||||
return spritePair.m_OverrideSprite;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
m_Sprites = m_Sprites.Where(spritePair => spritePair.m_OriginalSprite != originalSprite).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var spritePair in m_Sprites)
|
||||
{
|
||||
if (spritePair.m_OriginalSprite == originalSprite)
|
||||
{
|
||||
spritePair.m_OverrideSprite = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_Sprites.Add(new TileSpritePair { m_OriginalSprite = originalSprite, m_OverrideSprite = value });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RuleTile.TilingRule this[RuleTile.TilingRule originalRule]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!m_Tile)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var index = m_Tile.m_TilingRules.IndexOf(originalRule);
|
||||
if (index == -1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (m_OverrideTilingRules.Count < index + 1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return m_OverrideTilingRules[index].m_Enabled ? m_OverrideTilingRules[index].m_TilingRule : null;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!m_Tile)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var index = m_Tile.m_TilingRules.IndexOf(originalRule);
|
||||
if (index == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
if (m_OverrideTilingRules.Count < index + 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_OverrideTilingRules[index].m_Enabled = false;
|
||||
while (m_OverrideTilingRules.Count > 0 && !m_OverrideTilingRules[m_OverrideTilingRules.Count - 1].m_Enabled)
|
||||
{
|
||||
m_OverrideTilingRules.RemoveAt(m_OverrideTilingRules.Count - 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (m_OverrideTilingRules.Count < index + 1)
|
||||
{
|
||||
m_OverrideTilingRules.Add(new OverrideTilingRule());
|
||||
}
|
||||
m_OverrideTilingRules[index].m_Enabled = true;
|
||||
m_OverrideTilingRules[index].m_TilingRule = CloneTilingRule(value);
|
||||
m_OverrideTilingRules[index].m_TilingRule.m_Neighbors = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RuleTile.TilingRule m_OriginalDefault
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RuleTile.TilingRule
|
||||
{
|
||||
m_Sprites = new[] { m_Tile != null ? m_Tile.m_DefaultSprite : null },
|
||||
m_ColliderType = m_Tile != null ? m_Tile.m_DefaultColliderType : Tile.ColliderType.None
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override bool GetTileAnimationData(Vector3Int position, ITilemap tilemap, ref TileAnimationData tileAnimationData)
|
||||
{
|
||||
if (!m_RuntimeTile)
|
||||
{
|
||||
Override();
|
||||
}
|
||||
return m_RuntimeTile.GetTileAnimationData(position, tilemap, ref tileAnimationData);
|
||||
}
|
||||
|
||||
public override void GetTileData(Vector3Int position, ITilemap tilemap, ref TileData tileData)
|
||||
{
|
||||
if (!m_RuntimeTile)
|
||||
{
|
||||
Override();
|
||||
}
|
||||
m_RuntimeTile.GetTileData(position, tilemap, ref tileData);
|
||||
}
|
||||
|
||||
public override void RefreshTile(Vector3Int position, ITilemap tilemap)
|
||||
{
|
||||
if (!m_RuntimeTile)
|
||||
{
|
||||
Override();
|
||||
}
|
||||
m_RuntimeTile.RefreshTile(position, tilemap);
|
||||
}
|
||||
|
||||
public override bool StartUp(Vector3Int position, ITilemap tilemap, GameObject go)
|
||||
{
|
||||
Override();
|
||||
return m_RuntimeTile.StartUp(position, tilemap, go);
|
||||
}
|
||||
|
||||
public void ApplyOverrides(IList<KeyValuePair<Sprite, Sprite>> overrides)
|
||||
{
|
||||
if (overrides == null)
|
||||
{
|
||||
throw new ArgumentNullException("overrides");
|
||||
}
|
||||
|
||||
for (var i = 0; i < overrides.Count; i++)
|
||||
{
|
||||
this[overrides[i].Key] = overrides[i].Value;
|
||||
}
|
||||
}
|
||||
|
||||
public void GetOverrides(List<KeyValuePair<Sprite, Sprite>> overrides)
|
||||
{
|
||||
if (overrides == null)
|
||||
{
|
||||
throw new ArgumentNullException("overrides");
|
||||
}
|
||||
|
||||
overrides.Clear();
|
||||
|
||||
if (!m_Tile)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var originalSprites = new List<Sprite>();
|
||||
|
||||
if (m_Tile.m_DefaultSprite)
|
||||
{
|
||||
originalSprites.Add(m_Tile.m_DefaultSprite);
|
||||
}
|
||||
|
||||
foreach (var rule in m_Tile.m_TilingRules)
|
||||
foreach (var sprite in rule.m_Sprites)
|
||||
{
|
||||
if (sprite && !originalSprites.Contains(sprite))
|
||||
{
|
||||
originalSprites.Add(sprite);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var sprite in originalSprites)
|
||||
{
|
||||
overrides.Add(new KeyValuePair<Sprite, Sprite>(sprite, this[sprite]));
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyOverrides(IList<KeyValuePair<RuleTile.TilingRule, RuleTile.TilingRule>> overrides)
|
||||
{
|
||||
if (overrides == null)
|
||||
{
|
||||
throw new ArgumentNullException("overrides");
|
||||
}
|
||||
|
||||
for (var i = 0; i < overrides.Count; i++)
|
||||
{
|
||||
this[overrides[i].Key] = overrides[i].Value;
|
||||
}
|
||||
}
|
||||
|
||||
public void GetOverrides(List<KeyValuePair<RuleTile.TilingRule, RuleTile.TilingRule>> overrides)
|
||||
{
|
||||
if (overrides == null)
|
||||
{
|
||||
throw new ArgumentNullException("overrides");
|
||||
}
|
||||
|
||||
overrides.Clear();
|
||||
|
||||
if (!m_Tile)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var originalRule in m_Tile.m_TilingRules)
|
||||
{
|
||||
var overrideRule = this[originalRule];
|
||||
overrides.Add(new KeyValuePair<RuleTile.TilingRule, RuleTile.TilingRule>(originalRule, overrideRule));
|
||||
}
|
||||
|
||||
overrides.Add(new KeyValuePair<RuleTile.TilingRule, RuleTile.TilingRule>(m_OriginalDefault, m_OverrideDefault.m_TilingRule));
|
||||
}
|
||||
|
||||
public void Override()
|
||||
{
|
||||
m_RuntimeTile = m_Tile ? Instantiate(m_Tile) : new RuleTile();
|
||||
m_RuntimeTile.m_Self = this;
|
||||
if (!m_Advanced)
|
||||
{
|
||||
if (m_RuntimeTile.m_DefaultSprite)
|
||||
{
|
||||
m_RuntimeTile.m_DefaultSprite = this[m_RuntimeTile.m_DefaultSprite];
|
||||
}
|
||||
if (m_RuntimeTile.m_TilingRules != null)
|
||||
{
|
||||
foreach (var rule in m_RuntimeTile.m_TilingRules)
|
||||
{
|
||||
for (var i = 0; i < rule.m_Sprites.Length; i++)
|
||||
{
|
||||
if (rule.m_Sprites[i])
|
||||
{
|
||||
rule.m_Sprites[i] = this[rule.m_Sprites[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_OverrideDefault.m_Enabled)
|
||||
{
|
||||
m_RuntimeTile.m_DefaultSprite = m_OverrideDefault.m_TilingRule.m_Sprites.Length > 0
|
||||
? m_OverrideDefault.m_TilingRule.m_Sprites[0]
|
||||
: null;
|
||||
m_RuntimeTile.m_DefaultColliderType = m_OverrideDefault.m_TilingRule.m_ColliderType;
|
||||
}
|
||||
|
||||
if (m_RuntimeTile.m_TilingRules != null)
|
||||
{
|
||||
for (var i = 0; i < m_RuntimeTile.m_TilingRules.Count; i++)
|
||||
{
|
||||
var originalRule = m_RuntimeTile.m_TilingRules[i];
|
||||
var overrideRule = this[m_Tile.m_TilingRules[i]];
|
||||
if (overrideRule == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
CopyTilingRule(overrideRule, originalRule, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RuleTile.TilingRule CloneTilingRule(RuleTile.TilingRule from)
|
||||
{
|
||||
var clone = new RuleTile.TilingRule();
|
||||
CopyTilingRule(from, clone, true);
|
||||
return clone;
|
||||
}
|
||||
|
||||
public void CopyTilingRule(RuleTile.TilingRule from, RuleTile.TilingRule to, bool copyRule)
|
||||
{
|
||||
if (copyRule)
|
||||
{
|
||||
to.m_Neighbors = from.m_Neighbors;
|
||||
to.m_RuleTransform = from.m_RuleTransform;
|
||||
}
|
||||
|
||||
to.m_Sprites = from.m_Sprites.Clone() as Sprite[];
|
||||
to.m_AnimationSpeed = from.m_AnimationSpeed;
|
||||
to.m_PerlinScale = from.m_PerlinScale;
|
||||
to.m_Output = from.m_Output;
|
||||
to.m_ColliderType = from.m_ColliderType;
|
||||
to.m_RandomTransform = from.m_RandomTransform;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class TileSpritePair
|
||||
{
|
||||
public Sprite m_OriginalSprite;
|
||||
public Sprite m_OverrideSprite;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class OverrideTilingRule
|
||||
{
|
||||
public bool m_Enabled;
|
||||
public RuleTile.TilingRule m_TilingRule = new RuleTile.TilingRule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4c779848d9dd029409ca676b49e10a18
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/Tiles/Rule Tile.meta
Normal file
10
Assets/Scripts/UI/Tilemap/Tiles/Rule Tile.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8f0e4a19192261d448b776e63139448e
|
||||
folderAsset: yes
|
||||
timeCreated: 1501789590
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/Tiles/Rule Tile/Scripts.meta
Normal file
10
Assets/Scripts/UI/Tilemap/Tiles/Rule Tile/Scripts.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6d62b55c63b75aa468f7dc342717b87f
|
||||
folderAsset: yes
|
||||
timeCreated: 1501789661
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 32b801acc992cb24298d963cc554c0a2
|
||||
folderAsset: yes
|
||||
timeCreated: 1501789682
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,402 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using UnityEditor.Sprites;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using UnityEngine.Tilemaps;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace UnityEditor
|
||||
{
|
||||
[CustomEditor(typeof(RuleTile))]
|
||||
[CanEditMultipleObjects]
|
||||
internal class RuleTileEditor : Editor
|
||||
{
|
||||
private const string s_XIconString = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAABoSURBVDhPnY3BDcAgDAOZhS14dP1O0x2C/LBEgiNSHvfwyZabmV0jZRUpq2zi6f0DJwdcQOEdwwDLypF0zHLMa9+NQRxkQ+ACOT2STVw/q8eY1346ZlE54sYAhVhSDrjwFymrSFnD2gTZpls2OvFUHAAAAABJRU5ErkJggg==";
|
||||
private const string s_Arrow0 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAACYSURBVDhPzZExDoQwDATzE4oU4QXXcgUFj+YxtETwgpMwXuFcwMFSRMVKKwzZcWzhiMg91jtg34XIntkre5EaT7yjjhI9pOD5Mw5k2X/DdUwFr3cQ7Pu23E/BiwXyWSOxrNqx+ewnsayam5OLBtbOGPUM/r93YZL4/dhpR/amwByGFBz170gNChA6w5bQQMqramBTgJ+Z3A58WuWejPCaHQAAAABJRU5ErkJggg==";
|
||||
private const string s_Arrow1 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAABqSURBVDhPxYzBDYAgEATpxYcd+PVr0fZ2siZrjmMhFz6STIiDs8XMlpEyi5RkO/d66TcgJUB43JfNBqRkSEYDnYjhbKD5GIUkDqRDwoH3+NgTAw+bL/aoOP4DOgH+iwECEt+IlFmkzGHlAYKAWF9R8zUnAAAAAElFTkSuQmCC";
|
||||
private const string s_Arrow2 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAAC0SURBVDhPjVE5EsIwDMxPKFKYF9CagoJH8xhaMskLmEGsjOSRkBzYmU2s9a58TUQUmCH1BWEHweuKP+D8tphrWcAHuIGrjPnPNY8X2+DzEWE+FzrdrkNyg2YGNNfRGlyOaZDJOxBrDhgOowaYW8UW0Vau5ZkFmXbbDr+CzOHKmLinAXMEePyZ9dZkZR+s5QX2O8DY3zZ/sgYcdDqeEVp8516o0QQV1qeMwg6C91toYoLoo+kNt/tpKQEVvFQAAAAASUVORK5CYII=";
|
||||
private const string s_Arrow3 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAAB2SURBVDhPzY1LCoAwEEPnLi48gW5d6p31bH5SMhp0Cq0g+CCLxrzRPqMZ2pRqKG4IqzJc7JepTlbRZXYpWTg4RZE1XAso8VHFKNhQuTjKtZvHUNCEMogO4K3BhvMn9wP4EzoPZ3n0AGTW5fiBVzLAAYTP32C2Ay3agtu9V/9PAAAAAElFTkSuQmCC";
|
||||
private const string s_Arrow5 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAABqSURBVDhPnY3BCYBADASvFx924NevRdvbyoLBmNuDJQMDGjNxAFhK1DyUQ9fvobCdO+j7+sOKj/uSB+xYHZAxl7IR1wNTXJeVcaAVU+614uWfCT9mVUhknMlxDokd15BYsQrJFHeUQ0+MB5ErsPi/6hO1AAAAAElFTkSuQmCC";
|
||||
private const string s_Arrow6 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAACaSURBVDhPxZExEkAwEEVzE4UiTqClUDi0w2hlOIEZsV82xCZmQuPPfFn8t1mirLWf7S5flQOXjd64vCuEKWTKVt+6AayH3tIa7yLg6Qh2FcKFB72jBgJeziA1CMHzeaNHjkfwnAK86f3KUafU2ClHIJSzs/8HHLv09M3SaMCxS7ljw/IYJWzQABOQZ66x4h614ahTCL/WT7BSO51b5Z5hSx88AAAAAElFTkSuQmCC";
|
||||
private const string s_Arrow7 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAABQSURBVDhPYxh8QNle/T8U/4MKEQdAmsz2eICx6W530gygr2aQBmSMphkZYxqErAEXxusKfAYQ7XyyNMIAsgEkaYQBkAFkaYQBsjXSGDAwAAD193z4luKPrAAAAABJRU5ErkJggg==";
|
||||
private const string s_Arrow8 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAACYSURBVDhPxZE9DoAwCIW9iUOHegJXHRw8tIdx1egJTMSHAeMPaHSR5KVQ+KCkCRF91mdz4VDEWVzXTBgg5U1N5wahjHzXS3iFFVRxAygNVaZxJ6VHGIl2D6oUXP0ijlJuTp724FnID1Lq7uw2QM5+thoKth0N+GGyA7IA3+yM77Ag1e2zkey5gCdAg/h8csy+/89v7E+YkgUntOWeVt2SfAAAAABJRU5ErkJggg==";
|
||||
private const string s_MirrorX = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwQAADsEBuJFr7QAAABh0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC41ZYUyZQAAAG1JREFUOE+lj9ENwCAIRB2IFdyRfRiuDSaXAF4MrR9P5eRhHGb2Gxp2oaEjIovTXSrAnPNx6hlgyCZ7o6omOdYOldGIZhAziEmOTSfigLV0RYAB9y9f/7kO8L3WUaQyhCgz0dmCL9CwCw172HgBeyG6oloC8fAAAAAASUVORK5CYII=";
|
||||
private const string s_MirrorY = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABh0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC41ZYUyZQAAAG9JREFUOE+djckNACEMAykoLdAjHbPyw1IOJ0L7mAejjFlm9hspyd77Kk+kBAjPOXcakJIh6QaKyOE0EB5dSPJAiUmOiL8PMVGxugsP/0OOib8vsY8yYwy6gRyC8CB5QIWgCMKBLgRSkikEUr5h6wOPWfMoCYILdgAAAABJRU5ErkJggg==";
|
||||
private const string s_Rotated = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwQAADsEBuJFr7QAAABh0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC41ZYUyZQAAAHdJREFUOE+djssNwCAMQxmIFdgx+2S4Vj4YxWlQgcOT8nuG5u5C732Sd3lfLlmPMR4QhXgrTQaimUlA3EtD+CJlBuQ7aUAUMjEAv9gWCQNEPhHJUkYfZ1kEpcxDzioRzGIlr0Qwi0r+Q5rTgM+AAVcygHgt7+HtBZs/2QVWP8ahAAAAAElFTkSuQmCC";
|
||||
|
||||
private static Texture2D[] s_Arrows;
|
||||
public static Texture2D[] arrows
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_Arrows == null)
|
||||
{
|
||||
s_Arrows = new Texture2D[10];
|
||||
s_Arrows[0] = Base64ToTexture(s_Arrow0);
|
||||
s_Arrows[1] = Base64ToTexture(s_Arrow1);
|
||||
s_Arrows[2] = Base64ToTexture(s_Arrow2);
|
||||
s_Arrows[3] = Base64ToTexture(s_Arrow3);
|
||||
s_Arrows[5] = Base64ToTexture(s_Arrow5);
|
||||
s_Arrows[6] = Base64ToTexture(s_Arrow6);
|
||||
s_Arrows[7] = Base64ToTexture(s_Arrow7);
|
||||
s_Arrows[8] = Base64ToTexture(s_Arrow8);
|
||||
s_Arrows[9] = Base64ToTexture(s_XIconString);
|
||||
}
|
||||
return s_Arrows;
|
||||
}
|
||||
}
|
||||
|
||||
private static Texture2D[] s_AutoTransforms;
|
||||
public static Texture2D[] autoTransforms
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_AutoTransforms == null)
|
||||
{
|
||||
s_AutoTransforms = new Texture2D[3];
|
||||
s_AutoTransforms[0] = Base64ToTexture(s_Rotated);
|
||||
s_AutoTransforms[1] = Base64ToTexture(s_MirrorX);
|
||||
s_AutoTransforms[2] = Base64ToTexture(s_MirrorY);
|
||||
}
|
||||
return s_AutoTransforms;
|
||||
}
|
||||
}
|
||||
|
||||
private ReorderableList m_ReorderableList;
|
||||
public RuleTile tile { get { return (target as RuleTile); } }
|
||||
private Rect m_ListRect;
|
||||
|
||||
internal const float k_DefaultElementHeight = 48f;
|
||||
internal const float k_PaddingBetweenRules = 13f;
|
||||
internal const float k_SingleLineHeight = 16f;
|
||||
internal const float k_LabelWidth = 53f;
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
if (tile.m_TilingRules == null)
|
||||
tile.m_TilingRules = new List<RuleTile.TilingRule>();
|
||||
|
||||
m_ReorderableList = new ReorderableList(tile.m_TilingRules, typeof(RuleTile.TilingRule), true, true, true, true);
|
||||
m_ReorderableList.drawHeaderCallback = OnDrawHeader;
|
||||
m_ReorderableList.drawElementCallback = OnDrawElement;
|
||||
m_ReorderableList.elementHeightCallback = GetElementHeight;
|
||||
m_ReorderableList.onReorderCallback = ListUpdated;
|
||||
m_ReorderableList.onAddCallback = OnAddElement;
|
||||
}
|
||||
|
||||
private void ListUpdated(ReorderableList list)
|
||||
{
|
||||
SaveTile();
|
||||
}
|
||||
|
||||
private float GetElementHeight(int index)
|
||||
{
|
||||
if (tile.m_TilingRules != null && tile.m_TilingRules.Count > 0)
|
||||
{
|
||||
switch (tile.m_TilingRules[index].m_Output)
|
||||
{
|
||||
case RuleTile.TilingRule.OutputSprite.Random:
|
||||
return k_DefaultElementHeight + k_SingleLineHeight*(tile.m_TilingRules[index].m_Sprites.Length + 3) + k_PaddingBetweenRules;
|
||||
case RuleTile.TilingRule.OutputSprite.Animation:
|
||||
return k_DefaultElementHeight + k_SingleLineHeight*(tile.m_TilingRules[index].m_Sprites.Length + 2) + k_PaddingBetweenRules;
|
||||
}
|
||||
}
|
||||
return k_DefaultElementHeight + k_PaddingBetweenRules;
|
||||
}
|
||||
|
||||
private void OnDrawElement(Rect rect, int index, bool isactive, bool isfocused)
|
||||
{
|
||||
RuleTile.TilingRule rule = tile.m_TilingRules[index];
|
||||
|
||||
float yPos = rect.yMin + 2f;
|
||||
float height = rect.height - k_PaddingBetweenRules;
|
||||
float matrixWidth = k_DefaultElementHeight;
|
||||
|
||||
Rect inspectorRect = new Rect(rect.xMin, yPos, rect.width - matrixWidth * 2f - 20f, height);
|
||||
Rect matrixRect = new Rect(rect.xMax - matrixWidth * 2f - 10f, yPos, matrixWidth, k_DefaultElementHeight);
|
||||
Rect spriteRect = new Rect(rect.xMax - matrixWidth - 5f, yPos, matrixWidth, k_DefaultElementHeight);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
RuleInspectorOnGUI(inspectorRect, rule);
|
||||
RuleMatrixOnGUI(matrixRect, rule);
|
||||
SpriteOnGUI(spriteRect, rule);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
SaveTile();
|
||||
}
|
||||
|
||||
private void OnAddElement(ReorderableList list)
|
||||
{
|
||||
RuleTile.TilingRule rule = new RuleTile.TilingRule();
|
||||
rule.m_Output = RuleTile.TilingRule.OutputSprite.Single;
|
||||
rule.m_Sprites[0] = tile.m_DefaultSprite;
|
||||
rule.m_ColliderType = tile.m_DefaultColliderType;
|
||||
tile.m_TilingRules.Add(rule);
|
||||
}
|
||||
|
||||
private void SaveTile()
|
||||
{
|
||||
EditorUtility.SetDirty(target);
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
|
||||
private void OnDrawHeader(Rect rect)
|
||||
{
|
||||
GUI.Label(rect, "Tiling Rules");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
tile.m_DefaultSprite = EditorGUILayout.ObjectField("Default Sprite", tile.m_DefaultSprite, typeof(Sprite), false) as Sprite;
|
||||
tile.m_DefaultColliderType = (Tile.ColliderType)EditorGUILayout.EnumPopup("Default Collider", tile.m_DefaultColliderType);
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (m_ReorderableList != null && tile.m_TilingRules != null)
|
||||
m_ReorderableList.DoLayoutList();
|
||||
}
|
||||
|
||||
internal static void RuleMatrixOnGUI(Rect rect, RuleTile.TilingRule tilingRule)
|
||||
{
|
||||
Handles.color = EditorGUIUtility.isProSkin ? new Color(1f, 1f, 1f, 0.2f) : new Color(0f, 0f, 0f, 0.2f);
|
||||
int index = 0;
|
||||
float w = rect.width / 3f;
|
||||
float h = rect.height / 3f;
|
||||
|
||||
for (int y = 0; y <= 3; y++)
|
||||
{
|
||||
float top = rect.yMin + y * h;
|
||||
Handles.DrawLine(new Vector3(rect.xMin, top), new Vector3(rect.xMax, top));
|
||||
}
|
||||
for (int x = 0; x <= 3; x++)
|
||||
{
|
||||
float left = rect.xMin + x * w;
|
||||
Handles.DrawLine(new Vector3(left, rect.yMin), new Vector3(left, rect.yMax));
|
||||
}
|
||||
Handles.color = Color.white;
|
||||
|
||||
for (int y = 0; y <= 2; y++)
|
||||
{
|
||||
for (int x = 0; x <= 2; x++)
|
||||
{
|
||||
Rect r = new Rect(rect.xMin + x * w, rect.yMin + y * h, w - 1, h - 1);
|
||||
if (x != 1 || y != 1)
|
||||
{
|
||||
switch (tilingRule.m_Neighbors[index])
|
||||
{
|
||||
case RuleTile.TilingRule.Neighbor.This:
|
||||
GUI.DrawTexture(r, arrows[y*3 + x]);
|
||||
break;
|
||||
case RuleTile.TilingRule.Neighbor.NotThis:
|
||||
GUI.DrawTexture(r, arrows[9]);
|
||||
break;
|
||||
}
|
||||
if (Event.current.type == EventType.MouseDown && r.Contains(Event.current.mousePosition))
|
||||
{
|
||||
int change = 1;
|
||||
if (Event.current.button == 1)
|
||||
change = -1;
|
||||
tilingRule.m_Neighbors[index] = (RuleTile.TilingRule.Neighbor) (((int)tilingRule.m_Neighbors[index] + change) % 3);
|
||||
GUI.changed = true;
|
||||
Event.current.Use();
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (tilingRule.m_RuleTransform)
|
||||
{
|
||||
case RuleTile.TilingRule.Transform.Rotated:
|
||||
GUI.DrawTexture(r, autoTransforms[0]);
|
||||
break;
|
||||
case RuleTile.TilingRule.Transform.MirrorX:
|
||||
GUI.DrawTexture(r, autoTransforms[1]);
|
||||
break;
|
||||
case RuleTile.TilingRule.Transform.MirrorY:
|
||||
GUI.DrawTexture(r, autoTransforms[2]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (Event.current.type == EventType.MouseDown && r.Contains(Event.current.mousePosition))
|
||||
{
|
||||
tilingRule.m_RuleTransform = (RuleTile.TilingRule.Transform)(((int)tilingRule.m_RuleTransform + 1) % 4);
|
||||
GUI.changed = true;
|
||||
Event.current.Use();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnSelect(object userdata)
|
||||
{
|
||||
MenuItemData data = (MenuItemData) userdata;
|
||||
data.m_Rule.m_RuleTransform = data.m_NewValue;
|
||||
}
|
||||
|
||||
private class MenuItemData
|
||||
{
|
||||
public RuleTile.TilingRule m_Rule;
|
||||
public RuleTile.TilingRule.Transform m_NewValue;
|
||||
|
||||
public MenuItemData(RuleTile.TilingRule mRule, RuleTile.TilingRule.Transform mNewValue)
|
||||
{
|
||||
this.m_Rule = mRule;
|
||||
this.m_NewValue = mNewValue;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void SpriteOnGUI(Rect rect, RuleTile.TilingRule tilingRule)
|
||||
{
|
||||
tilingRule.m_Sprites[0] = EditorGUI.ObjectField(new Rect(rect.xMax - rect.height, rect.yMin, rect.height, rect.height), tilingRule.m_Sprites[0], typeof (Sprite), false) as Sprite;
|
||||
}
|
||||
|
||||
internal static void RuleInspectorOnGUI(Rect rect, RuleTile.TilingRule tilingRule)
|
||||
{
|
||||
float y = rect.yMin;
|
||||
EditorGUI.BeginChangeCheck();
|
||||
GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Rule");
|
||||
tilingRule.m_RuleTransform = (RuleTile.TilingRule.Transform)EditorGUI.EnumPopup(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), tilingRule.m_RuleTransform);
|
||||
y += k_SingleLineHeight;
|
||||
GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Collider");
|
||||
tilingRule.m_ColliderType = (Tile.ColliderType)EditorGUI.EnumPopup(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), tilingRule.m_ColliderType);
|
||||
y += k_SingleLineHeight;
|
||||
GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Output");
|
||||
tilingRule.m_Output = (RuleTile.TilingRule.OutputSprite)EditorGUI.EnumPopup(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), tilingRule.m_Output);
|
||||
y += k_SingleLineHeight;
|
||||
|
||||
if (tilingRule.m_Output == RuleTile.TilingRule.OutputSprite.Animation)
|
||||
{
|
||||
GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Speed");
|
||||
tilingRule.m_AnimationSpeed = EditorGUI.FloatField(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), tilingRule.m_AnimationSpeed);
|
||||
y += k_SingleLineHeight;
|
||||
}
|
||||
if (tilingRule.m_Output == RuleTile.TilingRule.OutputSprite.Random)
|
||||
{
|
||||
GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Noise");
|
||||
tilingRule.m_PerlinScale = EditorGUI.Slider(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), tilingRule.m_PerlinScale, 0.001f, 0.999f);
|
||||
y += k_SingleLineHeight;
|
||||
|
||||
GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Shuffle");
|
||||
tilingRule.m_RandomTransform = (RuleTile.TilingRule.Transform)EditorGUI.EnumPopup(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), tilingRule.m_RandomTransform);
|
||||
y += k_SingleLineHeight;
|
||||
}
|
||||
|
||||
if (tilingRule.m_Output != RuleTile.TilingRule.OutputSprite.Single)
|
||||
{
|
||||
GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Size");
|
||||
EditorGUI.BeginChangeCheck();
|
||||
int newLength = EditorGUI.DelayedIntField(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), tilingRule.m_Sprites.Length);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
Array.Resize(ref tilingRule.m_Sprites, Math.Max(newLength, 1));
|
||||
y += k_SingleLineHeight;
|
||||
|
||||
for (int i = 0; i < tilingRule.m_Sprites.Length; i++)
|
||||
{
|
||||
tilingRule.m_Sprites[i] = EditorGUI.ObjectField(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), tilingRule.m_Sprites[i], typeof(Sprite), false) as Sprite;
|
||||
y += k_SingleLineHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override Texture2D RenderStaticPreview(string assetPath, Object[] subAssets, int width, int height)
|
||||
{
|
||||
if (tile.m_DefaultSprite != null)
|
||||
{
|
||||
Type t = GetType("UnityEditor.SpriteUtility");
|
||||
if (t != null)
|
||||
{
|
||||
MethodInfo method = t.GetMethod("RenderStaticPreview", new Type[] {typeof (Sprite), typeof (Color), typeof (int), typeof (int)});
|
||||
if (method != null)
|
||||
{
|
||||
object ret = method.Invoke("RenderStaticPreview", new object[] {tile.m_DefaultSprite, Color.white, width, height});
|
||||
if (ret is Texture2D)
|
||||
return ret as Texture2D;
|
||||
}
|
||||
}
|
||||
}
|
||||
return base.RenderStaticPreview(assetPath, subAssets, width, height);
|
||||
}
|
||||
|
||||
private static Type GetType(string TypeName)
|
||||
{
|
||||
var type = Type.GetType(TypeName);
|
||||
if (type != null)
|
||||
return type;
|
||||
|
||||
if (TypeName.Contains("."))
|
||||
{
|
||||
var assemblyName = TypeName.Substring(0, TypeName.IndexOf('.'));
|
||||
var assembly = Assembly.Load(assemblyName);
|
||||
if (assembly == null)
|
||||
return null;
|
||||
type = assembly.GetType(TypeName);
|
||||
if (type != null)
|
||||
return type;
|
||||
}
|
||||
|
||||
var currentAssembly = Assembly.GetExecutingAssembly();
|
||||
var referencedAssemblies = currentAssembly.GetReferencedAssemblies();
|
||||
foreach (var assemblyName in referencedAssemblies)
|
||||
{
|
||||
var assembly = Assembly.Load(assemblyName);
|
||||
if (assembly != null)
|
||||
{
|
||||
type = assembly.GetType(TypeName);
|
||||
if (type != null)
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Texture2D Base64ToTexture(string base64)
|
||||
{
|
||||
Texture2D t = new Texture2D(1, 1);
|
||||
t.hideFlags = HideFlags.HideAndDontSave;
|
||||
t.LoadImage(System.Convert.FromBase64String(base64));
|
||||
return t;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
class RuleTileRuleWrapper
|
||||
{
|
||||
[SerializeField]
|
||||
public List<RuleTile.TilingRule> rules = new List<RuleTile.TilingRule>();
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/RuleTile/Copy All Rules")]
|
||||
private static void CopyAllRules(MenuCommand item)
|
||||
{
|
||||
RuleTile tile = item.context as RuleTile;
|
||||
if (tile == null)
|
||||
return;
|
||||
|
||||
RuleTileRuleWrapper rulesWrapper = new RuleTileRuleWrapper();
|
||||
rulesWrapper.rules = tile.m_TilingRules;
|
||||
var rulesJson = EditorJsonUtility.ToJson(rulesWrapper);
|
||||
EditorGUIUtility.systemCopyBuffer = rulesJson;
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/RuleTile/Paste Rules")]
|
||||
private static void PasteRules(MenuCommand item)
|
||||
{
|
||||
RuleTile tile = item.context as RuleTile;
|
||||
if (tile == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
RuleTileRuleWrapper rulesWrapper = new RuleTileRuleWrapper();
|
||||
EditorJsonUtility.FromJsonOverwrite(EditorGUIUtility.systemCopyBuffer, rulesWrapper);
|
||||
tile.m_TilingRules.AddRange(rulesWrapper.rules);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError("Unable to paste rules from system copy buffer");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 139f9377103555b49b8dcd62686df3bf
|
||||
timeCreated: 1501789622
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
333
Assets/Scripts/UI/Tilemap/Tiles/Rule Tile/Scripts/RuleTile.cs
Normal file
333
Assets/Scripts/UI/Tilemap/Tiles/Rule Tile/Scripts/RuleTile.cs
Normal file
|
|
@ -0,0 +1,333 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Tilemaps;
|
||||
|
||||
namespace UnityEngine
|
||||
{
|
||||
[Serializable, CreateAssetMenu]
|
||||
public class RuleTile : TileBase
|
||||
{
|
||||
private static readonly int[,] RotatedOrMirroredIndexes =
|
||||
{
|
||||
{ 2, 4, 7, 1, 6, 0, 3, 5 }, // 90
|
||||
{ 7, 6, 5, 4, 3, 2, 1, 0 }, // 180, XY
|
||||
{ 5, 3, 0, 6, 1, 7, 4, 2 }, // 270
|
||||
{ 2, 1, 0, 4, 3, 7, 6, 5 }, // X
|
||||
{ 5, 6, 7, 3, 4, 0, 1, 2 } // Y
|
||||
};
|
||||
|
||||
private static readonly int NeighborCount = 8;
|
||||
public Tile.ColliderType m_DefaultColliderType = Tile.ColliderType.Sprite;
|
||||
|
||||
public Sprite m_DefaultSprite;
|
||||
|
||||
[HideInInspector] public List<TilingRule> m_TilingRules;
|
||||
|
||||
private TileBase[] m_CachedNeighboringTiles = new TileBase[NeighborCount];
|
||||
private TileBase m_OverrideSelf;
|
||||
|
||||
public TileBase m_Self
|
||||
{
|
||||
get => m_OverrideSelf ? m_OverrideSelf : this;
|
||||
set => m_OverrideSelf = value;
|
||||
}
|
||||
|
||||
public override void GetTileData(Vector3Int position, ITilemap tilemap, ref TileData tileData)
|
||||
{
|
||||
TileBase[] neighboringTiles = null;
|
||||
GetMatchingNeighboringTiles(tilemap, position, ref neighboringTiles);
|
||||
var iden = Matrix4x4.identity;
|
||||
|
||||
tileData.sprite = m_DefaultSprite;
|
||||
tileData.colliderType = m_DefaultColliderType;
|
||||
tileData.flags = TileFlags.LockTransform;
|
||||
tileData.transform = iden;
|
||||
|
||||
foreach (var rule in m_TilingRules)
|
||||
{
|
||||
var transform = iden;
|
||||
if (RuleMatches(rule, ref neighboringTiles, ref transform))
|
||||
{
|
||||
switch (rule.m_Output)
|
||||
{
|
||||
case TilingRule.OutputSprite.Single:
|
||||
case TilingRule.OutputSprite.Animation:
|
||||
tileData.sprite = rule.m_Sprites[0];
|
||||
break;
|
||||
|
||||
case TilingRule.OutputSprite.Random:
|
||||
var index = Mathf.Clamp(
|
||||
Mathf.FloorToInt(GetPerlinValue(position, rule.m_PerlinScale, 100000f) * rule.m_Sprites.Length),
|
||||
0,
|
||||
rule.m_Sprites.Length - 1);
|
||||
tileData.sprite = rule.m_Sprites[index];
|
||||
if (rule.m_RandomTransform != TilingRule.Transform.Fixed)
|
||||
{
|
||||
transform = ApplyRandomTransform(rule.m_RandomTransform, transform, rule.m_PerlinScale, position);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
tileData.transform = transform;
|
||||
tileData.colliderType = rule.m_ColliderType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static float GetPerlinValue(Vector3Int position, float scale, float offset)
|
||||
{
|
||||
return Mathf.PerlinNoise((position.x + offset) * scale, (position.y + offset) * scale);
|
||||
}
|
||||
|
||||
public override bool GetTileAnimationData(Vector3Int position, ITilemap tilemap, ref TileAnimationData tileAnimationData)
|
||||
{
|
||||
TileBase[] neighboringTiles = null;
|
||||
var iden = Matrix4x4.identity;
|
||||
foreach (var rule in m_TilingRules)
|
||||
{
|
||||
if (rule.m_Output == TilingRule.OutputSprite.Animation)
|
||||
{
|
||||
var transform = iden;
|
||||
GetMatchingNeighboringTiles(tilemap, position, ref neighboringTiles);
|
||||
if (RuleMatches(rule, ref neighboringTiles, ref transform))
|
||||
{
|
||||
tileAnimationData.animatedSprites = rule.m_Sprites;
|
||||
tileAnimationData.animationSpeed = rule.m_AnimationSpeed;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void RefreshTile(Vector3Int location, ITilemap tileMap)
|
||||
{
|
||||
if (m_TilingRules != null && m_TilingRules.Count > 0)
|
||||
{
|
||||
for (var y = -1; y <= 1; y++)
|
||||
for (var x = -1; x <= 1; x++)
|
||||
{
|
||||
base.RefreshTile(location + new Vector3Int(x, y, 0), tileMap);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
base.RefreshTile(location, tileMap);
|
||||
}
|
||||
}
|
||||
|
||||
public bool RuleMatches(TilingRule rule, ref TileBase[] neighboringTiles, ref Matrix4x4 transform)
|
||||
{
|
||||
// Check rule against rotations of 0, 90, 180, 270
|
||||
for (var angle = 0; angle <= (rule.m_RuleTransform == TilingRule.Transform.Rotated ? 270 : 0); angle += 90)
|
||||
{
|
||||
if (RuleMatches(rule, ref neighboringTiles, angle))
|
||||
{
|
||||
transform = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, -angle), Vector3.one);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check rule against x-axis mirror
|
||||
if (rule.m_RuleTransform == TilingRule.Transform.MirrorX && RuleMatches(rule, ref neighboringTiles, true, false))
|
||||
{
|
||||
transform = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(-1f, 1f, 1f));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check rule against y-axis mirror
|
||||
if (rule.m_RuleTransform == TilingRule.Transform.MirrorY && RuleMatches(rule, ref neighboringTiles, false, true))
|
||||
{
|
||||
transform = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1f, -1f, 1f));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Matrix4x4 ApplyRandomTransform(TilingRule.Transform type, Matrix4x4 original, float perlinScale, Vector3Int position)
|
||||
{
|
||||
var perlin = GetPerlinValue(position, perlinScale, 200000f);
|
||||
switch (type)
|
||||
{
|
||||
case TilingRule.Transform.MirrorX:
|
||||
return original * Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(perlin < 0.5 ? 1f : -1f, 1f, 1f));
|
||||
|
||||
case TilingRule.Transform.MirrorY:
|
||||
return original * Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1f, perlin < 0.5 ? 1f : -1f, 1f));
|
||||
|
||||
case TilingRule.Transform.Rotated:
|
||||
var angle = Mathf.Clamp(Mathf.FloorToInt(perlin * 4), 0, 3) * 90;
|
||||
return Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, -angle), Vector3.one);
|
||||
}
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
public bool RuleMatches(TilingRule rule, ref TileBase[] neighboringTiles, int angle)
|
||||
{
|
||||
for (var i = 0; i < NeighborCount; ++i)
|
||||
{
|
||||
var index = GetRotatedIndex(i, angle);
|
||||
var tile = neighboringTiles[index];
|
||||
if (rule.m_Neighbors[i] == TilingRule.Neighbor.This && tile != m_Self ||
|
||||
rule.m_Neighbors[i] == TilingRule.Neighbor.NotThis && tile == m_Self)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool RuleMatches(TilingRule rule, ref TileBase[] neighboringTiles, bool mirrorX, bool mirrorY)
|
||||
{
|
||||
for (var i = 0; i < NeighborCount; ++i)
|
||||
{
|
||||
var index = GetMirroredIndex(i, mirrorX, mirrorY);
|
||||
var tile = neighboringTiles[index];
|
||||
if (rule.m_Neighbors[i] == TilingRule.Neighbor.This && tile != m_Self ||
|
||||
rule.m_Neighbors[i] == TilingRule.Neighbor.NotThis && tile == m_Self)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void GetMatchingNeighboringTiles(ITilemap tilemap, Vector3Int position, ref TileBase[] neighboringTiles)
|
||||
{
|
||||
if (neighboringTiles != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_CachedNeighboringTiles == null || m_CachedNeighboringTiles.Length < NeighborCount)
|
||||
{
|
||||
m_CachedNeighboringTiles = new TileBase[NeighborCount];
|
||||
}
|
||||
|
||||
var index = 0;
|
||||
for (var y = 1; y >= -1; y--)
|
||||
for (var x = -1; x <= 1; x++)
|
||||
{
|
||||
if (x != 0 || y != 0)
|
||||
{
|
||||
var tilePosition = new Vector3Int(position.x + x, position.y + y, position.z);
|
||||
m_CachedNeighboringTiles[index++] = tilemap.GetTile(tilePosition);
|
||||
}
|
||||
}
|
||||
|
||||
neighboringTiles = m_CachedNeighboringTiles;
|
||||
}
|
||||
|
||||
private int GetRotatedIndex(int original, int rotation)
|
||||
{
|
||||
switch (rotation)
|
||||
{
|
||||
case 0:
|
||||
return original;
|
||||
|
||||
case 90:
|
||||
return RotatedOrMirroredIndexes[0, original];
|
||||
|
||||
case 180:
|
||||
return RotatedOrMirroredIndexes[1, original];
|
||||
|
||||
case 270:
|
||||
return RotatedOrMirroredIndexes[2, original];
|
||||
}
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
private int GetMirroredIndex(int original, bool mirrorX, bool mirrorY)
|
||||
{
|
||||
if (mirrorX && mirrorY)
|
||||
{
|
||||
return RotatedOrMirroredIndexes[1, original];
|
||||
}
|
||||
if (mirrorX)
|
||||
{
|
||||
return RotatedOrMirroredIndexes[3, original];
|
||||
}
|
||||
if (mirrorY)
|
||||
{
|
||||
return RotatedOrMirroredIndexes[4, original];
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
private int GetIndexOfOffset(Vector3Int offset)
|
||||
{
|
||||
var result = offset.x + 1 + (-offset.y + 1) * 3;
|
||||
if (result >= 4)
|
||||
{
|
||||
result--;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Vector3Int GetRotatedPos(Vector3Int original, int rotation)
|
||||
{
|
||||
switch (rotation)
|
||||
{
|
||||
case 0:
|
||||
return original;
|
||||
|
||||
case 90:
|
||||
return new Vector3Int(-original.y, original.x, original.z);
|
||||
|
||||
case 180:
|
||||
return new Vector3Int(-original.x, -original.y, original.z);
|
||||
|
||||
case 270:
|
||||
return new Vector3Int(original.y, -original.x, original.z);
|
||||
}
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
public Vector3Int GetMirroredPos(Vector3Int original, bool mirrorX, bool mirrorY)
|
||||
{
|
||||
return new Vector3Int(original.x * (mirrorX ? -1 : 1), original.y * (mirrorY ? -1 : 1), original.z);
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class TilingRule
|
||||
{
|
||||
public enum Neighbor { DontCare, This, NotThis }
|
||||
|
||||
public enum OutputSprite { Single, Random, Animation }
|
||||
|
||||
public enum Transform { Fixed, Rotated, MirrorX, MirrorY }
|
||||
|
||||
public float m_AnimationSpeed;
|
||||
public Tile.ColliderType m_ColliderType;
|
||||
public Neighbor[] m_Neighbors;
|
||||
public OutputSprite m_Output;
|
||||
public float m_PerlinScale;
|
||||
public Transform m_RandomTransform;
|
||||
public Transform m_RuleTransform;
|
||||
public Sprite[] m_Sprites;
|
||||
|
||||
public TilingRule()
|
||||
{
|
||||
m_Output = OutputSprite.Single;
|
||||
m_Neighbors = new Neighbor[NeighborCount];
|
||||
m_Sprites = new Sprite[1];
|
||||
m_AnimationSpeed = 1f;
|
||||
m_PerlinScale = 0.5f;
|
||||
m_ColliderType = Tile.ColliderType.Sprite;
|
||||
|
||||
for (var i = 0; i < m_Neighbors.Length; i++)
|
||||
{
|
||||
m_Neighbors[i] = Neighbor.DontCare;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9d1514134bc4fbd41bb739b1b9a49231
|
||||
timeCreated: 1501789622
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/Tiles/Terrain Tile.meta
Normal file
10
Assets/Scripts/UI/Tilemap/Tiles/Terrain Tile.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7f83a174d475ee842aaea9ee552fa506
|
||||
folderAsset: yes
|
||||
timeCreated: 1499149439
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/UI/Tilemap/Tiles/Terrain Tile/Scripts.meta
Normal file
10
Assets/Scripts/UI/Tilemap/Tiles/Terrain Tile/Scripts.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 14fc4c2dd67018d41b00db847f45f5dd
|
||||
folderAsset: yes
|
||||
timeCreated: 1499149468
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
using System;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
|
||||
#endif
|
||||
|
||||
namespace UnityEngine.Tilemaps
|
||||
{
|
||||
[Serializable]
|
||||
public class TerrainTile : TileBase
|
||||
{
|
||||
[SerializeField] public Sprite[] m_Sprites;
|
||||
|
||||
public override void RefreshTile(Vector3Int location, ITilemap tileMap)
|
||||
{
|
||||
for (var yd = -1; yd <= 1; yd++)
|
||||
for (var xd = -1; xd <= 1; xd++)
|
||||
{
|
||||
var position = new Vector3Int(location.x + xd, location.y + yd, location.z);
|
||||
if (TileValue(tileMap, position))
|
||||
{
|
||||
tileMap.RefreshTile(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void GetTileData(Vector3Int location, ITilemap tileMap, ref TileData tileData)
|
||||
{
|
||||
UpdateTile(location, tileMap, ref tileData);
|
||||
}
|
||||
|
||||
private void UpdateTile(Vector3Int location, ITilemap tileMap, ref TileData tileData)
|
||||
{
|
||||
tileData.transform = Matrix4x4.identity;
|
||||
tileData.color = Color.white;
|
||||
|
||||
var mask = TileValue(tileMap, location + new Vector3Int(0, 1, 0)) ? 1 : 0;
|
||||
mask += TileValue(tileMap, location + new Vector3Int(1, 1, 0)) ? 2 : 0;
|
||||
mask += TileValue(tileMap, location + new Vector3Int(1, 0, 0)) ? 4 : 0;
|
||||
mask += TileValue(tileMap, location + new Vector3Int(1, -1, 0)) ? 8 : 0;
|
||||
mask += TileValue(tileMap, location + new Vector3Int(0, -1, 0)) ? 16 : 0;
|
||||
mask += TileValue(tileMap, location + new Vector3Int(-1, -1, 0)) ? 32 : 0;
|
||||
mask += TileValue(tileMap, location + new Vector3Int(-1, 0, 0)) ? 64 : 0;
|
||||
mask += TileValue(tileMap, location + new Vector3Int(-1, 1, 0)) ? 128 : 0;
|
||||
|
||||
var original = (byte)mask;
|
||||
if ((original | 254) < 255)
|
||||
{
|
||||
mask = mask & 125;
|
||||
}
|
||||
if ((original | 251) < 255)
|
||||
{
|
||||
mask = mask & 245;
|
||||
}
|
||||
if ((original | 239) < 255)
|
||||
{
|
||||
mask = mask & 215;
|
||||
}
|
||||
if ((original | 191) < 255)
|
||||
{
|
||||
mask = mask & 95;
|
||||
}
|
||||
|
||||
var index = GetIndex((byte)mask);
|
||||
if (index >= 0 && index < m_Sprites.Length && TileValue(tileMap, location))
|
||||
{
|
||||
tileData.sprite = m_Sprites[index];
|
||||
tileData.transform = GetTransform((byte)mask);
|
||||
tileData.color = Color.white;
|
||||
tileData.flags = TileFlags.LockTransform | TileFlags.LockColor;
|
||||
tileData.colliderType = Tile.ColliderType.Sprite;
|
||||
}
|
||||
}
|
||||
|
||||
private bool TileValue(ITilemap tileMap, Vector3Int position)
|
||||
{
|
||||
var tile = tileMap.GetTile(position);
|
||||
return tile != null && tile == this;
|
||||
}
|
||||
|
||||
private int GetIndex(byte mask)
|
||||
{
|
||||
switch (mask)
|
||||
{
|
||||
case 0: return 0;
|
||||
|
||||
case 1:
|
||||
case 4:
|
||||
case 16:
|
||||
case 64: return 1;
|
||||
|
||||
case 5:
|
||||
case 20:
|
||||
case 80:
|
||||
case 65: return 2;
|
||||
|
||||
case 7:
|
||||
case 28:
|
||||
case 112:
|
||||
case 193: return 3;
|
||||
|
||||
case 17:
|
||||
case 68: return 4;
|
||||
|
||||
case 21:
|
||||
case 84:
|
||||
case 81:
|
||||
case 69: return 5;
|
||||
|
||||
case 23:
|
||||
case 92:
|
||||
case 113:
|
||||
case 197: return 6;
|
||||
|
||||
case 29:
|
||||
case 116:
|
||||
case 209:
|
||||
case 71: return 7;
|
||||
|
||||
case 31:
|
||||
case 124:
|
||||
case 241:
|
||||
case 199: return 8;
|
||||
|
||||
case 85: return 9;
|
||||
|
||||
case 87:
|
||||
case 93:
|
||||
case 117:
|
||||
case 213: return 10;
|
||||
|
||||
case 95:
|
||||
case 125:
|
||||
case 245:
|
||||
case 215: return 11;
|
||||
|
||||
case 119:
|
||||
case 221: return 12;
|
||||
|
||||
case 127:
|
||||
case 253:
|
||||
case 247:
|
||||
case 223: return 13;
|
||||
|
||||
case 255: return 14;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private Matrix4x4 GetTransform(byte mask)
|
||||
{
|
||||
switch (mask)
|
||||
{
|
||||
case 4:
|
||||
case 20:
|
||||
case 28:
|
||||
case 68:
|
||||
case 84:
|
||||
case 92:
|
||||
case 116:
|
||||
case 124:
|
||||
case 93:
|
||||
case 125:
|
||||
case 221:
|
||||
case 253:
|
||||
return Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, -90f), Vector3.one);
|
||||
|
||||
case 16:
|
||||
case 80:
|
||||
case 112:
|
||||
case 81:
|
||||
case 113:
|
||||
case 209:
|
||||
case 241:
|
||||
case 117:
|
||||
case 245:
|
||||
case 247:
|
||||
return Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, -180f), Vector3.one);
|
||||
|
||||
case 64:
|
||||
case 65:
|
||||
case 193:
|
||||
case 69:
|
||||
case 197:
|
||||
case 71:
|
||||
case 199:
|
||||
case 213:
|
||||
case 215:
|
||||
case 223:
|
||||
return Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, -270f), Vector3.one);
|
||||
}
|
||||
|
||||
return Matrix4x4.identity;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[MenuItem("Assets/Create/Terrain Tile")]
|
||||
public static void CreateTerrainTile()
|
||||
{
|
||||
var path = EditorUtility.SaveFilePanelInProject("Save Terrain Tile", "New Terrain Tile", "asset", "Save Terrain Tile", "Assets");
|
||||
|
||||
if (path == "")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AssetDatabase.CreateAsset(CreateInstance<TerrainTile>(), path);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[CustomEditor(typeof(TerrainTile))]
|
||||
public class TerrainTileEditor : Editor
|
||||
{
|
||||
private TerrainTile tile => target as TerrainTile;
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
if (tile.m_Sprites == null || tile.m_Sprites.Length != 15)
|
||||
{
|
||||
tile.m_Sprites = new Sprite[15];
|
||||
EditorUtility.SetDirty(tile);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.LabelField("Place sprites shown based on the contents of the sprite.");
|
||||
EditorGUILayout.Space();
|
||||
|
||||
var oldLabelWidth = EditorGUIUtility.labelWidth;
|
||||
EditorGUIUtility.labelWidth = 210;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
tile.m_Sprites[0] = (Sprite)EditorGUILayout.ObjectField("Filled", tile.m_Sprites[0], typeof(Sprite), false, null);
|
||||
tile.m_Sprites[1] = (Sprite)EditorGUILayout.ObjectField("Three Sides", tile.m_Sprites[1], typeof(Sprite), false, null);
|
||||
tile.m_Sprites[2] = (Sprite)EditorGUILayout.ObjectField("Two Sides and One Corner", tile.m_Sprites[2], typeof(Sprite), false, null);
|
||||
tile.m_Sprites[3] = (Sprite)EditorGUILayout.ObjectField("Two Adjacent Sides", tile.m_Sprites[3], typeof(Sprite), false, null);
|
||||
tile.m_Sprites[4] = (Sprite)EditorGUILayout.ObjectField("Two Opposite Sides", tile.m_Sprites[4], typeof(Sprite), false, null);
|
||||
tile.m_Sprites[5] = (Sprite)EditorGUILayout.ObjectField("One Side and Two Corners", tile.m_Sprites[5], typeof(Sprite), false, null);
|
||||
tile.m_Sprites[6] = (Sprite)EditorGUILayout.ObjectField("One Side and One Lower Corner", tile.m_Sprites[6], typeof(Sprite), false, null);
|
||||
tile.m_Sprites[7] = (Sprite)EditorGUILayout.ObjectField("One Side and One Upper Corner", tile.m_Sprites[7], typeof(Sprite), false, null);
|
||||
tile.m_Sprites[8] = (Sprite)EditorGUILayout.ObjectField("One Side", tile.m_Sprites[8], typeof(Sprite), false, null);
|
||||
tile.m_Sprites[9] = (Sprite)EditorGUILayout.ObjectField("Four Corners", tile.m_Sprites[9], typeof(Sprite), false, null);
|
||||
tile.m_Sprites[10] = (Sprite)EditorGUILayout.ObjectField("Three Corners", tile.m_Sprites[10], typeof(Sprite), false, null);
|
||||
tile.m_Sprites[11] = (Sprite)EditorGUILayout.ObjectField("Two Adjacent Corners", tile.m_Sprites[11], typeof(Sprite), false, null);
|
||||
tile.m_Sprites[12] = (Sprite)EditorGUILayout.ObjectField("Two Opposite Corners", tile.m_Sprites[12], typeof(Sprite), false, null);
|
||||
tile.m_Sprites[13] = (Sprite)EditorGUILayout.ObjectField("One Corner", tile.m_Sprites[13], typeof(Sprite), false, null);
|
||||
tile.m_Sprites[14] = (Sprite)EditorGUILayout.ObjectField("Empty", tile.m_Sprites[14], typeof(Sprite), false, null);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
EditorUtility.SetDirty(tile);
|
||||
}
|
||||
|
||||
EditorGUIUtility.labelWidth = oldLabelWidth;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f6e4e4fc705376343a3e65b25d94f0e2
|
||||
timeCreated: 1464534739
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4ec81e1e269ae1d4787784bf0e950f5f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
using System;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
|
||||
#endif
|
||||
|
||||
namespace UnityEngine.Tilemaps
|
||||
{
|
||||
[Serializable]
|
||||
public struct WeightedSprite
|
||||
{
|
||||
public Sprite Sprite;
|
||||
public int Weight;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class WeightedRandomTile : Tile
|
||||
{
|
||||
[SerializeField] public WeightedSprite[] Sprites;
|
||||
|
||||
public override void GetTileData(Vector3Int location, ITilemap tileMap, ref TileData tileData)
|
||||
{
|
||||
base.GetTileData(location, tileMap, ref tileData);
|
||||
|
||||
if (Sprites == null || Sprites.Length <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
long hash = location.x;
|
||||
hash = hash + 0xabcd1234 + (hash << 15);
|
||||
hash = (hash + 0x0987efab) ^ (hash >> 11);
|
||||
hash ^= location.y;
|
||||
hash = hash + 0x46ac12fd + (hash << 7);
|
||||
hash = (hash + 0xbe9730af) ^ (hash << 11);
|
||||
Random.InitState((int)hash);
|
||||
|
||||
// Get the cumulative weight of the sprites
|
||||
var cumulativeWeight = 0;
|
||||
foreach (var spriteInfo in Sprites)
|
||||
{
|
||||
cumulativeWeight += spriteInfo.Weight;
|
||||
}
|
||||
|
||||
// Pick a random weight and choose a sprite depending on it
|
||||
var randomWeight = Random.Range(0, cumulativeWeight);
|
||||
foreach (var spriteInfo in Sprites)
|
||||
{
|
||||
randomWeight -= spriteInfo.Weight;
|
||||
if (randomWeight < 0)
|
||||
{
|
||||
tileData.sprite = spriteInfo.Sprite;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[MenuItem("Assets/Create/Weighted Random Tile")]
|
||||
public static void CreateRandomTile()
|
||||
{
|
||||
var path = EditorUtility.SaveFilePanelInProject(
|
||||
"Save Weighted Random Tile",
|
||||
"New Weighted Random Tile",
|
||||
"asset",
|
||||
"Save Weighted Random Tile",
|
||||
"Assets");
|
||||
|
||||
if (path == "")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AssetDatabase.CreateAsset(CreateInstance<WeightedRandomTile>(), path);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[CustomEditor(typeof(WeightedRandomTile))]
|
||||
public class WeightedRandomTileEditor : Editor
|
||||
{
|
||||
private WeightedRandomTile Tile => target as WeightedRandomTile;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
var count = EditorGUILayout.DelayedIntField("Number of Sprites", Tile.Sprites != null ? Tile.Sprites.Length : 0);
|
||||
if (count < 0)
|
||||
{
|
||||
count = 0;
|
||||
}
|
||||
|
||||
if (Tile.Sprites == null || Tile.Sprites.Length != count)
|
||||
{
|
||||
Array.Resize(ref Tile.Sprites, count);
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField("Place random sprites.");
|
||||
EditorGUILayout.Space();
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
Tile.Sprites[i].Sprite = (Sprite)EditorGUILayout.ObjectField(
|
||||
"Sprite " + (i + 1),
|
||||
Tile.Sprites[i].Sprite,
|
||||
typeof(Sprite),
|
||||
false,
|
||||
null);
|
||||
Tile.Sprites[i].Weight = EditorGUILayout.IntField("Weight " + (i + 1), Tile.Sprites[i].Weight);
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
EditorUtility.SetDirty(Tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1b859987a0026e2498a93cc8109d5b55
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue