Snippets

Alex Darby Enum Demo for Shane

Created by Alex Darby last modified
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

using UnityEngine;

public class ShaneEnumDemo : MonoBehaviour
{
	// enums are a super awesome way to do the same thing you're doing because they're both a 
	// readable string *and* a number & in C# it's trivial to convert between them
	public enum EMonster
	{
		Dragon,         // unless you say otherwise this will == 0
		Shoggoth,       // and the rest will go up by 1 to the end of the enum
		Yeti,           // you can convert to string with .ToString() and to int with a cast

		// ADD NEW VALUES ABOVE!
		COUNT           // this is the de facto standard way to know the number of values in an enum - it could be called anything
	}

	public enum EWeapon
	{
		Sword,  // unless you say otherwise this will == 0
		Axe,    // and the rest will go up by 1 to the end of the enum
		Dagger, // you can convert to string with .ToString() and to int with a cast
		Bow,

		// philosophically 'Nothing' represents the absence of a weapon
		// this seems counter intuitive but will make sense further down
		// for the code below to work you'd need to add all new values above this too 
		Nothing,

		// ADD NEW VALUES ABOVE!
		COUNT           // this is the de facto standard way to know the number of values in an enum - it could be called anything
	}

	public bool m_bDoItTheOldWay = true;

	[Tooltip( "0 == 0%; 1 == 100%")]
	[Range( 0.01f, 0.99f)]
	public float m_ChanceOfNoWeapon = 0.5f;

	[Tooltip( "add weapons you want to drop, more of the same weapon increases its chance of dropping" )]
	public EWeapon[] m_WeaponDropTable;


	private List< EWeapon > m_lstWeaponDropTable;


	void Start()
	{
		InitWeaponChanceLookupTable();
	}

	void Update()
	{
		EnumUtil.LogAllValuesToConsole<EMonster>();
		EnumUtil.LogAllValuesToConsole<EWeapon>();

		if( m_bDoItTheOldWay )
		{
			//
			// to do the random thing the way you were you could do this
			//
			int iRandomWeapon = UnityEngine.Random.Range( 0, ((int)EWeapon.COUNT) * 2 );

			// n.b. this relies on EWeapon.Nothing being AFTER all the other weapons in the enum
			if( iRandomWeapon < ( (int)EWeapon.Nothing ) )
			{
				Debug.LogFormat( "You found a {0}!", ( (EWeapon)iRandomWeapon ).ToString() );
			}
			else
			{
				// no weapon
				Debug.Log( "You didn't find anything!" );
			}

		}
		else
		{
			//
			// the way I'd do it uses the table built in InitWeaponChanceLookupTable() and it's naturally extensible
			// you add more weapons to the enum and it'll just keep working
			//
			EWeapon eDroppedWeapon = m_lstWeaponDropTable[ UnityEngine.Random.Range( 0, m_lstWeaponDropTable.Count ) ];

			switch( eDroppedWeapon )
			{
			case EWeapon.Nothing:
				Debug.Log( "You didn't find anything!" );
				break;

			default:
				Debug.LogFormat( "You found a {0}", eDroppedWeapon.ToString() );
				break;

			case EWeapon.COUNT:
				Debug.LogError( "You should never hit this code unless there's a bug!" );
				break;
			}
		}
	}

	void InitWeaponChanceLookupTable()
	{
		// or, here's another way, not necessarily qualitatively "better", but more extendible

		// this is how you declare an array of enum values
		//
		// N.B. you can also use them as public members, arrays, or lists in Unity 
		// and the editor will handle them automatically...
		//
		// N.N.B. so, you could totally just put it as apublic member and set it in the editor, 
		// or put it on a scriptable asset (https://unity3d.com/learn/tutorials/modules/beginner/live-training-archive/scriptable-objects)
		//
		// N.N.B. this check means that this'll work without you setting up values in the editor
		if( m_WeaponDropTable.Length == 0 )
		{
			m_WeaponDropTable = new EWeapon[]
			{
				// by varying the number of each in the array we change the likelihood of each one coming up
				EWeapon.Axe,
				EWeapon.Bow, EWeapon.Bow,
				EWeapon.Dagger,
				EWeapon.Sword, EWeapon.Sword, EWeapon.Sword,
			};
		}

		// now build a lookup list to give the stats wanted for finding a weapon
		// n.b. this constructor adds the array elenments into the list
		m_lstWeaponDropTable = new List<EWeapon>( m_WeaponDropTable );

		int     iTotalIncludingNothings     = Mathf.FloorToInt( ((float) m_lstWeaponDropTable.Count ) * ( 1f / m_ChanceOfNoWeapon ) );
		int     iNothingsToAdd              = ( iTotalIncludingNothings - m_lstWeaponDropTable.Count );

		// N.B. you might want to add 1 to iNothingsToAdd
		// or if you set m_ChanceOfNoWeapon too low you'll never actually get "no weapon" added
		for( int i = 0; i < iNothingsToAdd; ++i )
		{
			m_lstWeaponDropTable.Add( EWeapon.Nothing );
		}
	}
}

/////////////////////////////////////////////////////////////////////////////
public static class EnumUtil
{
	public static IEnumerable<TEnum> GetAllValues<TEnum>()
	where TEnum : struct, IConvertible, IComparable, IFormattable
	{
		return Enum.GetValues( typeof( TEnum ) ).Cast<TEnum>();
	}

	public static void LogAllValuesToConsole<TEnum>()
	where TEnum : struct, IConvertible, IComparable, IFormattable
	{
		var aeAllValues = EnumUtil.GetAllValues<TEnum>();

		foreach( TEnum eValue in aeAllValues )
		{
			System.Console.WriteLine( string.Format( "--> {0} [as int:{1}]", eValue.ToString(), eValue.ToUInt32( null ) ) );
		}
	}
}

Comments (0)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.