I am writing a game where a car drives and makes jumps. When a jump is landed, the player is rewarded if they land all four wheels either at the same time, or near to the same time. If they don't, they are penalised.I am concerned my solution is not well abstracted (although I am open to all topics of feedback), and particularly that it will not be very extensible in the future should I come to add additional things to check for (such as bonuses for good air time, or tricks) on landing.using System.Collections.Generic;using System.Linq;using UnityEngine;/// <summary>/// Checks if the car has made a good landing or not./// </summary>[RequireComponent(typeof(CollisionEvent))] //Unity engine code to ensure a CollisionEvent is always attached to the same object as this script.public class GoodLandingChecker : MonoBehaviour{    /// <summary>    /// Gets or sets the bad landing threshold.    /// When a bad landing occurs, the player is penalised.    /// </summary>    /// <value>    /// The bad landing threshold.    /// </value>    public float BadLandingThreshold    {        get { return badLandingThreshold; }        set { badLandingThreshold = value; }    }    /// <summary>    /// Gets or sets the good landing threshold.    /// When a good landing occurs, the player is rewarded.    /// </summary>    /// <value>    /// The good landing threshold.    /// </value>    public float GoodLandingThreshold    {        get { return goodLandingThreshold; }        set { goodLandingThreshold = value; }    }    /// <summary>    /// Gets or sets the great landing threshold.    /// When a great landing occurs, the player is rewarded greatly.    /// </summary>    /// <value>    /// The great landing threshold.    /// </value>    public float GreatLandingThreshold    {        get { return greatLandingThreshold; }        set { greatLandingThreshold = value; }    }    /// <summary>    /// Gets or sets the minimum flying time before a landing will be considered.    /// </summary>    /// <value>    /// The minimum flying time.    /// </value>    public float MinimumFlyingTime    {        get { return minFlyingTime; }        set { minFlyingTime = value; }    }    /// <summary>    /// Gets or sets the wheels used to calculate when landings happen.    /// </summary>    /// <value>    /// The wheels.    /// </value>    public List<Transform> Wheels    {        get { return wheels; }        set { wheels = value; }    }    /// <summary>    /// The bad landing threshold    /// </summary>    [SerializeField] //Unity code to make this private field show up in Unity's    //Inspector where its value is set by the designer. This is used because the    //Inspector cannot display properties.    private float badLandingThreshold;    /// <summary>    /// Flying checker is a separate class that simply checks if every wheel is touching the ground.    /// </summary>    [SerializeField]    private FlyingChecker flyingChecker;    /// <summary>    /// The time spent in the air since the last landing.    /// </summary>    private float flyingTime = 0f;    /// <summary>    /// The good landing threshold    /// </summary>    [SerializeField]    private float goodLandingThreshold;    /// <summary>    /// The great landing threshold    /// </summary>    [SerializeField]    private float greatLandingThreshold;    /// <summary>    /// Whether the car is flying right now or not.    /// </summary>    private bool isFlying = false;    /// <summary>    /// The minimum flying time before a landing will be considered.    /// </summary>    [SerializeField]    private float minFlyingTime;    /// <summary>    /// The wheels    /// </summary>    [SerializeField]    private List<Transform> wheels;    /// <summary>    /// Checks the angle of the car.    /// If it's fairly flat, a good landing is awarded.    /// </summary>    /// <param name=wheel>The wheel that landed.</param>    public void WheelLanded(Transform wheel)    {        if (isFlying && flyingTime >= minFlyingTime)        {            isFlying = false;            //Get height of other wheel            float wheelHeightDifference = Wheels.Where(x => x != wheel).Sum(x => Mathf.Abs(x.position.y - wheel.position.y));            if (wheelHeightDifference <= GreatLandingThreshold)            {                Debug.Log(Great!);                //Give the car a *huge* forward push                rigidbody.AddForce(transform.forward * 500000);            }            else if (wheelHeightDifference <= GoodLandingThreshold)            {                Debug.Log(Good);                //Give the car a forward push                rigidbody.AddForce(transform.forward * 200000);            }            else if (wheelHeightDifference >= BadLandingThreshold)            {                Debug.Log(Awful!);                //Give the car a backward push                rigidbody.AddForce(-transform.forward * 200000);            }            else            {                Debug.Log(Ok);                //Normal landing, ignore            }        }        flyingTime = 0f;    }    /// <summary>    /// Handles the CollisionEntered event of the GoodLandingChecker control.    /// This occurs when something has hit something.    /// </summary>    /// <param name=sender>The source of the event.</param>    /// <param name=e>The <see cref=Game.View.CollisionEventArgs/> instance containing the event data.</param>    private void GoodLandingChecker_CollisionEntered(object sender, Game.View.CollisionEventArgs e)    {        //Check whether any wheels hit the ground.        var wheel = Wheels.FirstOrDefault(w => e.Collision.contacts.Select(x => x.thisCollider).Any(x => w.collider == x));        if (wheel != null)        {            WheelLanded(wheel);        }    }    /// <summary>    /// Called when this object is destroyed by Unity.    /// </summary>    private void OnDestroy()    {        GetComponent<CollisionEvent>().CollisionEntered -= GoodLandingChecker_CollisionEntered;    }    /// <summary>    /// Called by Unity when the game starts.    /// </summary>    private void Start()    {        GetComponent<CollisionEvent>().CollisionEntered += GoodLandingChecker_CollisionEntered;    }    /// <summary>    /// Called by Unity every frame.    /// </summary>    private void Update()    {        //Flying checker is a separate class that simply checks if every wheel is touching the ground        isFlying = isFlying || flyingChecker.IsFlying();        if (isFlying)        {            flyingTime += Time.deltaTime;        }    }}
Determining vehicle jump landing quality
c#;game;unity3d;physics
First, I am not a C# programmer, but a Java programmer.  So maybe some of what I write here is wrong for C#.You write too many comments.  Let the code speak for itself.GoodLandingChecker_CollisionEntered  Are you supposed to use underscore notation in C#?You can probably find a better name for WheelLanded.  Either OnWheelLanded if it's a callback, or something which is a verb otherwise, ie analyzeLanding.I would split WheelLanded in a series of methods: a method that returns the height differencea method that transform the numerical height into an enumone (or many) delegates that register to the get the enum result.For example, the debugging print out and the added forward motion would be two separate delegates.I am not sure if FlyingChecker should be separated from this class.  Maybe you could have the method that determines what kind of landing (enum) it is in FlyingChecker, but have the delegates that act on that information being defined elsewhere.