This section explains all there is to know to create a new MMFeedback.

Creating a new feedback

Creating a new feedback is very easy. Create a new class, have it inherit from MMFeedback, and override the methods you’re interested in (usually CustomInitialization, CustomPlayFeedback, CustomStopFeedback and CustomReset). You can look at each feedback for a reference of how it’s done, they’re all heavily commented. Here’s a template you can use as a starting point :

using UnityEngine;
using MoreMountains.Tools;

namespace MoreMountains.Feedbacks
{
    [AddComponentMenu("")]
    [FeedbackHelp("You can add a description for your feedback here.")]
    [FeedbackPath("ChosenPath/MyFeedbackNameGoesHere")]
    public class MMF_DebugLog : MMF_Feedback
    {
        /// a static bool used to disable all feedbacks of this type at once
        public static bool FeedbackTypeAuthorized = true;
        /// use this override to specify the duration of your feedback (don't hesitate to look at other feedbacks for reference)
        public override float FeedbackDuration { get { return 0f; } }
        /// pick a color here for your feedback's inspector
    		#if UNITY_EDITOR
    			public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.DebugColor; } }
    		#endif

    		protected override void CustomInitialization(MMF_Player owner)
    		{
    			base.CustomInitialization(owner);
    			// your init code goes here
    		}

        protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
        {
            if (!Active || !FeedbackTypeAuthorized)
            {
                return;
            }            
            // your play code goes here
        }

        protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1)
        {
	        if (!FeedbackTypeAuthorized)
	        {
		        return;
	        }            
	        // your stop code goes here
        }
    }
}

Creating a new feedback (for the legacy MMFeedbacks system)

Creating a new feedback for the legacy system is also very simple. Here’s a template you can use as a starting point :

using UnityEngine;
using MoreMountains.Feedbacks;

[AddComponentMenu("")]
[FeedbackPath("ChosenPath/MyFeedbackNameGoesHere")]
public class MMFeedbackMyFeedbackNameGoesHere : MMFeedback
{
    // declare your variables here

    protected override void CustomInitialization(GameObject owner)
    {
        base.CustomInitialization(owner);
        if (Active)
        {
            // Put custom initialization code here
        }
    }

    protected override void CustomPlayFeedback(Vector3 position, float attenuation = 1.0f)
    {
        if (Active)
        {
            // Put custom play code here
        }
    }

    protected override void CustomStopFeedback(Vector3 position, float attenuation = 1)
    {
        base.CustomStopFeedback(position, attenuation);
        if (Active)
        {
            // Put custom stop code here
        }
    }

    protected override void CustomReset()
    {
        base.CustomReset();
        if (Active)
        {
            // Put custom reset code here
        }
    }
}


Modifying an existing feedback

Sometimes you find a feedback that does almost what you’re after, but not exactly. In situations like that, you have a few options :

  • create a new feedback entirely : this will work, but it may be a waste of time to redo everything another feedback already does, and it’ll make for a lot of duplicated code
  • modify the existing feedback : this is also possible, but you may lose your changes the next time you update Feel
  • inherit from the current feedback and change its behavior : that’s usually the recommended option, it’s the fastest, cleanest and safest way to do it

Inheriting from an existing feedback and extending it is done just like for any other class in C#. You can learn more about how it’s done in Unity’s documentation.

Let’s go over a simple example : let’s say we’re using the TextMeshPro Count To feedback to display our current in-game credits, maybe at the end of a level, to have that text display go from 0 to the collected amount. It’s all working fine, but we’d like to add a dollar sign at the end of it. Smarter people might say we could just add another text element next to it, with our dollar sign. But for the sake of the demonstration, what if we wanted to have the feedback itself add a suffix to the same text element?

That’s easily done with inheritance. The first thing to do is figure out what script to extend. The name of feedbacks in Feel always starts with the ‘MMF_’ prefix. You can usually find a feedback via the search bar in your editor’s Project panel, simply type its name. In our case, we want to extend MMF_TMPCountTo. Let’s do it :

using MoreMountains.Feedbacks;
using UnityEngine;

// here you specify how to access that feedback in the "Add Feedback" dropdown
[FeedbackPath("TextMesh Pro/TMP Count To With Suffix")] 

// we declare the name of our class, and specify it inherits from MMF_TMPCountTo
public class MMF_TMPCountToSuffix : MMF_TMPCountTo 
{
    // we want this new feedback to display a suffix, so we create a new string we'll add to our text
	public string Suffix = "$";
	
    // we override the UpdateText method, which is the only part of the feedback we want to change, 
    // the rest will behave as it did before
	protected override void UpdateText(float currentValue) 
	{
        // we call the base method, as we want it to run unchanged, we just want to do an extra thing at the end
        // of course that's not mandatory, and we could have changed entirely how that method behaves by simply not calling base
		base.UpdateText(currentValue);
        // we add our suffix to our TextMeshPro
		TargetTMPText.text = TargetTMPText.text + Suffix;
	}
}

Now we can just remove our old feedback, and start using this new one in its place. Extending feedbacks is a great way to use their existing power and adapt it to your exact project specs. If, while extending a feedback, you feel like the current feedback’s structure isn’t ideal, never hesitate to use the support form to request changes to it, Feel is designed to be extended upon, and is constantly improving on that aspect. All suggestions are welcome!

The MMFeedbackBase class

MMFeedbacks come with a base class you can extend if your use case applies. That abstract class is designed to handle cases where your feedback is meant to modify one or more values (float, vector, color, int, bool, etc) over time, or instantly. Good examples would be the alpha of a CanvasGroup, or the volume of an AudioSource.

If your use case matches, then using that class as a base will save you a lot of time. You can look at the MMFeedbackCanvasGroup for a reference of how it’s done.

using MoreMountains.Tools;
using UnityEngine;

namespace MoreMountains.Feedbacks
{
    /// <summary>
    /// This feedback lets you control the opacity of a canvas group over time
    /// </summary>
    [AddComponentMenu("")]
    // displays a help text in the inspector
    [FeedbackHelp("This feedback lets you control the opacity of a canvas group over time.")]
    // path to add the feedback in the Add Feedback dropdown
    [FeedbackPath("UI/CanvasGroup")]
    // IMPORTANT : we make sure we extend MMFeedbackBase
    public class MMFeedbackCanvasGroup : MMFeedbackBase
    {
        /// sets the inspector color for this feedback
#if UNITY_EDITOR
        public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.UIColor; } }
#endif

        // below we declare a number of properties that are specific to our use case
        // for each value you'll want to have a MMTweenType curve to move over, a target, remap zero and one values, and a value to apply on instant

        [Header("Target")]
        /// the receiver to write the level to
        public CanvasGroup TargetCanvasGroup;
        [Header("Level")]
        /// the curve to tween the intensity on
        [MMFEnumCondition("Mode", (int)MMFeedbackBase.Modes.OverTime, (int)MMFeedbackBase.Modes.ShakerEvent)]
        public MMTweenType AlphaCurve = new MMTweenType(new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.3f, 1f), new Keyframe(1, 0)));
        /// the value to remap the intensity curve's 0 to
        [MMFEnumCondition("Mode", (int)MMFeedbackBase.Modes.OverTime, (int)MMFeedbackBase.Modes.ShakerEvent)]
        public float RemapZero = 0f;
        /// the value to remap the intensity curve's 1 to
        [MMFEnumCondition("Mode", (int)MMFeedbackBase.Modes.OverTime, (int)MMFeedbackBase.Modes.ShakerEvent)]
        public float RemapOne = 1f;
        /// the value to move the intensity to in instant mode
        [MMFEnumCondition("Mode", (int)MMFeedbackBase.Modes.Instant)]
        public float InstantAlpha;

        // this method is where the magic happens.
        // we create a base target and a receiver. We bind our receiver's object and specify what property we want to impact on it
        // then we setup our MMFeedbackBaseTarget, and finally we add it to our list of targets. That's all!

        protected override void FillTargets()
        {
            if (TargetCanvasGroup == null)
            {
                return;
            }

            MMFeedbackBaseTarget target = new MMFeedbackBaseTarget();
            MMPropertyReceiver receiver = new MMPropertyReceiver();
            receiver.TargetObject = TargetCanvasGroup.gameObject;
            receiver.TargetComponent = TargetCanvasGroup;
            receiver.TargetPropertyName = "alpha";
            receiver.RelativeValue = RelativeValues;
            target.Target = receiver;
            target.LevelCurve = AlphaCurve;
            target.RemapLevelZero = RemapZero;
            target.RemapLevelOne = RemapOne;
            target.InstantLevel = InstantAlpha;

            _targets.Add(target);
        }

    }
}

Extensions Repository

If you create a new feedback and think others might benefit from it, or if you’re looking for more feedbacks or Feel tools, you can check the Feel Extensions Repository on Github. Contributions are of course always welcome!