Hello!

In unity i would generally have the following structure for something like interacting with objects.

(Pseudocodish)

public interface IInteractable
{
    public void OnInteract();
}
public class SomeClass : Monobehaviour, IInteractable
{
    public void OnInteract()
    {
         //do something
    }
}
public class Player : Monobehaviour
{
    void Update
    {
        if( button for interacting was pressed)
            Interact();
    }
    void Interact()
    {
        Colliders coliders = Physics.OverlapBox(playerposition,facingdirectionofplayer,distance,collisionlayer);
        foreach(Collider col in colliders)
        {
            if(col.Trygetcomponent(out IInteractable interactable))
                interactable.OnInteract();
        }
    }

}`

Something like this is easily applies for all kinds of things like damaging, healing etc.

How would you guys translate this into godot with c#?

    Moep

    In GDScript or C# you could use duck-typing.
    Specifically, you would check has_method. Then in GDScript you would just call the function like normal, but in C# you need to use call.

    In C# only, if your class implements IInteractable, you can use is or as to see if the thing you collided with implements the interface.

    For example:

        public override void _PhysicsProcess(double delta)
        {
            var collisionInfo = MoveAndCollide(_velocity * (float)delta);
            if (collisionInfo != null)
                for (int i = 0; i < collisionInfo.get_collision_count(); ++i) {
                    var interactable = collisionInfo.get_collider(i) as IInteractable;
                    if (interactable != null)
                        interactable.OnInteract();
                }
        }
    • Moep replied to this.

      award

      That is a good answer! Another solution i found was someone creating area2d/3d objects with a script that if the player enters, adds the interactable to a list of interactables inside the player and if the player presses interact it will go through the items and check for the closest one to call the function on. if the player leaves the area2d/3d it removes itself from that list.

      Reading up on Raycasts in godot i came up with one that is very similar on how you would do it in unity.

      public partial class PlayerScript : CharacterBody3D
      {
      	private RayCast3D interactionRaycast;
      	public override void _Ready()
      	{
      		InputManager.i.InteractPressedEventHandler += Interact;
      		interactionRaycast = (RayCast3D)GetNode("InteractRayCast3D");
      	}
      	private void Interact(object sender, EventArgs e)
      	{
      		GodotObject obj = interactionRaycast.GetCollider();
      
      		if (obj == null)
      			return;
      			
      		if (obj is IInteractable interactable)
      		{
      			interactable.OnInteract();
      		}
      	}
      	public override void _Process(double delta)
      	{
      	}
      }

      Something to note though. Many raycast nodes can be rather performance intensive from my research. So maybe enabling and disabling the raycast node would be required to save on performance. Currently im looking into how to raycast without the raycast node. Maybe i do a performance comparison later.

      Alright. Here is the version that is closest to the unity implementation that does not require an Raycast node.

      private void DoRaycastCheck()
      	{
      		PhysicsDirectSpaceState3D spaceState = GetWorld3D().DirectSpaceState;
      		PhysicsRayQueryParameters3D query = PhysicsRayQueryParameters3D.Create(GlobalPosition, GlobalPosition + GlobalTransform.Basis.Z *3);
      		query.CollideWithAreas = true;
      
      		var result = spaceState.IntersectRay(query);
      		if (result.Count > 0)
      		{	
      			GodotObject collider = result["collider"].AsGodotObject();
      
      			if (collider is IInteractable interactable)
      			{
      				interactable.OnInteract();
      			}
      		}
      	}
      
      	private void OnInteract(object sender, EventArgs e)
      	{
      		DoRaycastCheck();
      	}