0
\$\begingroup\$

I'm creating a platform system using a raycast controller that uses an interface to perform different tasks based on the type of platform with which my player is currently colliding. Some of the platform types include ice, passable blocks and muddy ground.

I want to know how to better optimize my code, as I currently call Unity's somewhat expensive "GetComponent()" function every frame, even if I never change between blocks. What I'd like to do is only call GetComponent() when I change from one type of platform to a different type of platform (i.e. muddy ground --> ice), but don't know how to do this using an interface.

I thought I would be able to compare types using enums, but you're not allowed to declare types in an interface.

        if (hit)
        {
            //I'd only like to run this block of code if the type of platform changes
            var platform = hit.collider.gameObject.GetComponent<IPlatform>();

            State.IsCollidingWithPassablePlatform = platform.IsPassable;
            State.IsJumpBoosted = platform.IsJumpForce;
            State.IsBoosted = platform.IsForce;

            xForce = platform.XForce;
            yForce = platform.YForce;
            zForce = platform.ZForce;

            defaultParameters.accelerationTimeGrounded = platform.AccelerationTimeGrounded;
            defaultParameters.accelerationTimeAirborne = platform.AccelerationTimeAirborne;

Interface example:

interface IPlatform {

float AccelerationTimeGrounded { get; }
float AccelerationTimeAirborne { get; }

float XForce { get; }
float YForce { get; }
float ZForce { get; }

bool IsPassable { get; }

bool IsForce { get; }
bool IsJumpForce { get; }

Ice platform:

public class PlatformIce : MonoBehaviour, IPlatform {

public float AccelerationTimeGrounded { get { return accelerationTimeGrounded; } }
public float AccelerationTimeAirborne { get { return accelerationTimeAirborne; } }

public float XForce { get { return xForce; } }
public float YForce { get { return yForce; } }
public float ZForce { get { return zForce; } }

public virtual bool IsPassable { get { return false; } }

public bool IsForce { get { return false; } }
public bool IsJumpForce { get { return false; } }

[SerializeField]
private float accelerationTimeGrounded = 1.0f;
[SerializeField]
private float accelerationTimeAirborne = 3.0f;

private float xForce = 0;
private float yForce = 0;
private float zForce = 0;
}
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

If your interface implementations differ only in the data they return from these getters, you might not need interfaces at all but a type object.

Then your platform script might be just an attachment point to glue this data structure to the game object:

public class Platform : MonoBehaviour {
    public PlatformProperties platformType;
}

And your PlatformProperties could be a ScriptableObject to make it easy to author in the editor and share between instances:

[CreateAssetMenu(fileName = "newPlatformProps.asset", menuName = "Level/Platform Properties")]
public class PlatformProperties : ScriptableObject {
    public Vector3 someProperty;
    // etc...
}

(You can of course use private serializable fields and getters to keep these things read-only if you want to enforce clean OOP here)

Determining whether the new platform is the same type as the old platform will still require getting a handle to the new platform — I can't tell you if "what's in the box" is the same as what's in my hand unless I open the box first.

But, we can at least detect whether we have a new box to open, rather than re-peeking into the same box every frame.

First, we cache the last platform collider and script we encountered:

Collider _lastCollider;
Platform _lastPlatform;

Then in your collision handling logic (be it an OnCollisionEnter or a raycast/other test)...

     // Do things like discarding non-foot collisions
     // and updating grounded state here.

    if(hit.collider == _lastCollider) {
         // no news, early-out.
         return;
    }

    // Look for a platform script on the new platform
    var platform = hit.collider.gameObject.GetComponent<Platform>();

     if(platform == null)
         return; // Not a platform.

     _lastCollider = hit.collider

      if(platform.platformType != _oldPlatform.platformType) {
          // Here we know it's a new type.
     }
     _oldPlatform = platform;

    // ... etc
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .