Interactions with Interfaces
My previous articles left off with some rapid prototyping for these pickups and other interaction mechanics. This article will clean up my code with interfaces, making it more scalable and designer friendly. Let’s get to it!
The player needs to be able to open and close this door with some input and an animation. The door object has an Animator, a Sphere Collider centered to the control panel, a Door script and an Interactable script.
The door Animator is a simple opening and closing animation that will use the IsOpen bool Parameter for the Transitions.
Each door prefab has a UI Transform prefab, which is the world space canvas used to show the interaction input to the player.
The interface used for all interactable items to inherit from, is a simple iInteractable class with a single Interact method, that all inheriting classes must implement.
public interface iInteractable
{
public void Interact();
}The Interactable script can get the Interface in void Start because it is on the same object via the Door or Collectable scripts being used for various interaction behaviors. Rather than running an OnTriggerStay method like in the previous articles, this version is just using OnTriggerEnter and Exit, plus the Input System to avoid running an update loop. If the player has entered the collider on the interactable object, it’s can Interact bool will be set to true, enabling the interact input to call the Interact method on the Interface.
using UnityEngine;
using UnityEngine.InputSystem;
public class Interactable : MonoBehaviour
{
[SerializeField] private GameObject _uiDisplay;
private iInteractable _interactable;
private InputActions _input;
[SerializeField] private bool _canInteract = false;
private void Start()
{
_interactable = GetComponent<iInteractable>();
_input = new InputActions();
if (_input != null)
_input.UI.Enable();
_input.UI.Interact.performed += Interact_performed;
}
private void OnDisable()
{
_input.UI.Interact.performed -= Interact_performed;
}
private void Interact_performed(InputAction.CallbackContext context)
{
//interact
if (_canInteract)
_interactable.Interact();
}
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Player"))
{
_canInteract = true;
_uiDisplay.SetActive(true);
}
}
private void OnTriggerExit(Collider other)
{
_canInteract = false;
_uiDisplay.SetActive(false);
}
}The Collectable script inherits from the iInteractable and implements the public Interact method. When the interactable script triggers it, the basic collectable behavior of instantiating a particle effect before it destroys itself will play out.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Collectable : MonoBehaviour, iInteractable
{
[SerializeField] private GameObject _particleFX;
public void Interact()
{
Debug.Log("Collectable Interaction");
if (_particleFX != null)
Instantiate(_particleFX, transform.position, Quaternion.identity);
Destroy(this.gameObject);
}
}The Door script also inherits from the interactable, and performs it’s opening and closing animation when it’s Interact method is run.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Door : MonoBehaviour, iInteractable
{
[SerializeField] private bool _isOpen = false;
[SerializeField] private Animator _animatior;
private void Start()
{
_animatior = GetComponent<Animator>();
if (_animatior == null)
Debug.LogWarning("The Animator on the Door " + gameObject.name + " is NULL");
}
public void Interact()
{
Debug.Log("Interacting with Door");
_isOpen = !_isOpen;
_animatior.SetBool("IsOpen", _isOpen);
}
}Please join me for my next article where these door interactions go further with locking and unlocking mechanics. Thanks for reading!
