Skip to content

Instantly share code, notes, and snippets.

@dallonf
Last active January 1, 2021 00:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dallonf/981648a6786d1a4bc0536cc4f8dfce85 to your computer and use it in GitHub Desktop.
Save dallonf/981648a6786d1a4bc0536cc4f8dfce85 to your computer and use it in GitHub Desktop.
Unity "Reconciler" system
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
[System.Serializable]
public abstract class BaseReconciler<TKey, TObject> : ISerializationCallbackReceiver where TObject : Object
{
private Dictionary<TKey, TObject> managedObjects;
private List<TObject> serializedManagedObjects;
public ICollection<KeyValuePair<TKey, TObject>> ManagedPairs
{
get { return managedObjects; }
}
public ICollection<TObject> ManagedObjects
{
get { return managedObjects.Values; }
}
public void Reconcile(IEnumerable<TKey> keys)
{
if (managedObjects == null)
{
managedObjects = new Dictionary<TKey, TObject>();
}
var lastKeys = managedObjects.Keys.ToList();
var keysToCreate = keys.Except(lastKeys);
var keysToRemove = lastKeys.Except(keys);
foreach (var item in keysToCreate)
{
var newObj = Create(item);
managedObjects.Add(item, newObj);
}
foreach (var item in keysToRemove)
{
Destroy(managedObjects[item]);
managedObjects.Remove(item);
}
}
public void Clear()
{
foreach (var pair in managedObjects)
{
Destroy(pair.Value);
}
managedObjects.Clear();
}
public void OnBeforeSerialize()
{
if (managedObjects != null)
{
serializedManagedObjects = managedObjects.Values.ToList();
}
}
public void OnAfterDeserialize()
{
if (serializedManagedObjects != null)
{
foreach (var item in serializedManagedObjects)
{
Destroy(item);
}
}
}
/// <summary>
/// Create a new TObject and put it in the scene. Must be overriden by the base class.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public abstract TObject Create(TKey key);
/// <summary>
/// Destroys a managed object. By default, calls Object.Destroy on it, but can be overridden.
/// </summary>
/// <param name="obj"></param>
protected virtual void Destroy(TObject obj)
{
if (obj)
{
Object.Destroy(obj);
}
}
}
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class InteractIconManager : MonoBehaviour
{
public Player Player;
public float IconVisibleRange = 100;
public InteractIcon InteractIconPrefab;
private InteractMode InteractMode;
InteractIconReconciler IconReconciler;
void Start()
{
Player = GetComponent<Player>();
IconReconciler = new InteractIconReconciler(this);
}
void FixedUpdate()
{
InteractMode = GetComponentInChildren<InteractMode>(true);
var interactables = FindObjectsOfType<Interactable>()
.Select(i => new { interactable = i, sqDistance = (i.transform.position - Player.transform.position).sqrMagnitude })
.Where(i => i.sqDistance < IconVisibleRange * IconVisibleRange);
IconReconciler.Reconcile(interactables.Select(i => i.interactable));
}
void OnDestroy()
{
IconReconciler.Clear();
}
[System.Serializable]
class InteractIconReconciler : BaseReconciler<Interactable, InteractIcon>
{
private InteractIconManager parent;
public InteractIconReconciler(InteractIconManager parent)
{
this.parent = parent;
}
public override InteractIcon Create(Interactable key)
{
var icon = Instantiate(parent.InteractIconPrefab, key.transform.position, Quaternion.identity) as InteractIcon;
icon.transform.position = key.transform.position;
icon.Interactable = key;
return icon;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment