Hi everyone! I’m trying to figure out how to code a chemistry system, what’s the better apporach to do this? Also I would be glad to know how would experienced developer handle these things?
- interface interaction. if object A which extend fire interface, collide with object B, if object B extend burnable interface, burn.
Fire
public interface IActor
{
public GameObject gameObject { get; }
public Transform transform { get; }
}
public class SimpleFire : MonoBehaviour, IActor, IFire
{
public bool Interact(IActor actor, IActor passive)
{
var burnable = actor.gameObject.GetComponent<IBurnable>();
if (burnable != null)
{
return burnable.Interact(actor, null);
}
return false;
}
private void OnTriggerStay2D(Collider2D other)
{
Debug.Log("trigger");
other.GetComponent<IBurnable>()?.Interact(this, null);
}
}
Burnable
public interface IInteraction
{
bool Interact(IActor actor, IActor passive);
}
public interface IBurnable : IInteraction{}
public class SimpleBurnable : MonoBehaviour, IBurnable
{
public bool Interact(IActor actor, IActor passive)
{
var fire = actor.gameObject.GetComponent<IFire>();
if (fire == null)
return false;
var ownFire = GetComponent<IFire>();
if (ownFire == null)
{
return Burn();
}
else
{
return false;
}
}
}
- Tag/Mask comparison. If object A has fire tag, and object B has burnable tag, when they collide, burn. Actually I’m using flag enum to define the tags belongs to the gameobject, also the requirement of the interaction.
I guess this one might better than the first one because it save a lot of work to do comparison by hand foreach new kind of interaction.
Code
[Flags]
public enum ChemistryMask
{
fire = 1,
burnable = 2,
water = 4,
}
public interface IChemistryLink
{
ChemistryMask Mask { get; }
DetectorType RequireDetectorType { get; }
public bool SameDetector(DetectorType detectorType) => detectorType == RequireDetectorType;
public bool Interact(ChemistryMask aMask, ChemistryMask bMask, GameObject a, GameObject b);
public bool Match(ChemistryMask a, ChemistryMask b)
{
return Mask == (Mask & (a | b));
}
}
public bool TryLink(ChemistryMask aChemistryMask, ChemistryMask bChemistryMask, GameObject a, GameObject b, DetectorType detector)
{
foreach (var chemistry in ChemistryNodes)
{
if (!chemistry.Match(aChemistryMask) && !chemistry.Match(bChemistryMask))
continue;
if (chemistry.Links == null) continue;
foreach (var link in chemistry.Links)
{
if (!link.Match(aChemistryMask, bChemistryMask))
continue;
if (!link.SameDetector(detector))
continue;
return link.Interact(aChemistryMask, bChemistryMask, a, b);
}
}
return false;
}
- This one is quite Date-Oriented I guess, it just change the internal value of a object, and use that value to decide whether is should burn. it seems amazingly simple… I can give everything interactive those kind of values.
Temperature
public class Temperature : MonoBehaviour
{
public float Value;
private bool unchanged; // Fire is unchanged.
private float changeSpeed;
// TODO Min Max limit
private bool Change(float target)
{
if (unchanged) return false;
var positive = Math.Sign(target - Value);
Value += positive * changeSpeed * Time.deltaTime;
return true;
}
private void Update()
{
var temperature = GetComponent<Temperature>();
if (temperature.Value > 100)
{
// burn;
}
}
private void Balance(Temperature other)
{
Change(other.Value);
}
private void OnTriggerStay2D(Collider2D other)
{
if (other.TryGetComponent<Temperature>(out var temperature))
Change(temperature.Value);
}
}
I want to know which one is better? From both the aspect of performance and extensible. Are there any ptifalls?
Hope I convey my question well, if anyone can shed some insight for me, I would be very appreciated! Thanks!