Skip to content

Instantly share code, notes, and snippets.

@joethephish
Created July 1, 2020 16:40
Show Gist options
  • Save joethephish/2cecc517ef036c21dcc00f959740b519 to your computer and use it in GitHub Desktop.
Save joethephish/2cecc517ef036c21dcc00f959740b519 to your computer and use it in GitHub Desktop.
Class to wrap single tweakable float value for UI that depends on platform. Could be hacked/adapted for something other than input type/platform.
using System;
using UnityEngine;
/// <summary>
/// PlatformFloat is an easy way of providing platform-specific tweak values.
/// By default, it behaves exactly like a normal float, and is converted back and forth
/// from a normal float implicitly.
/// However, in the inspector its possible to use a dropdown to provide platform
/// specific values for desktop, gamepad and touch.
/// </summary>
[Flags]
public enum PlatformValuePresence {
NonSpecific = 0,
Desktop = 1,
Gamepad = 2,
Mobile = 4,
All = ~0
}
[Serializable]
public class PlatformFloat : ISerializationCallbackReceiver {
[SerializeField] PlatformValuePresence presence;
public float desktopAndFallbackValue;
public bool isNonSpecific {
get {
return presence == PlatformValuePresence.NonSpecific;
}
}
public bool hasDesktopValue {
get { return (presence & PlatformValuePresence.Desktop) > 0; }
set {
if( value )
presence |= PlatformValuePresence.Desktop;
else
presence &= ~PlatformValuePresence.Desktop;
}
}
public float gamepadValue;
public bool hasGamepadValue {
get { return (presence & PlatformValuePresence.Gamepad) > 0; }
set {
if( value )
presence |= PlatformValuePresence.Gamepad;
else
presence &= ~PlatformValuePresence.Gamepad;
}
}
public float mobileValue;
public bool hasMobileValue {
get { return (presence & PlatformValuePresence.Mobile) > 0; }
set {
if( value )
presence |= PlatformValuePresence.Mobile;
else
presence &= ~PlatformValuePresence.Mobile;
}
}
public float current { get; private set; }
public void OnAfterDeserialize() {
RefreshCurrentValue();
InputController.OnChangeInputTypeEarly -= OnChangeInput;
InputController.OnChangeInputTypeEarly += OnChangeInput;
}
PlatformFloat() {
RefreshCurrentValue();
InputController.OnChangeInputTypeEarly -= OnChangeInput;
InputController.OnChangeInputTypeEarly += OnChangeInput;
}
~PlatformFloat() {
InputController.OnChangeInputTypeEarly -= OnChangeInput;
}
public void OnBeforeSerialize() {
}
void OnChangeInput(InputController.InputType newInputType)
{
RefreshCurrentValue();
}
void RefreshCurrentValue()
{
current = ChooseCurrentValue();
}
float ChooseCurrentValue() {
if( !InputController.IsInitialized ) return desktopAndFallbackValue;
var inputType = InputController.inputType;
if( inputType == InputController.InputType.KeyboardAndMouse ) {
if( isNonSpecific || hasDesktopValue )
return desktopAndFallbackValue;
else if( hasGamepadValue )
return gamepadValue;
else
return mobileValue;
} else if( inputType == InputController.InputType.Gamepad ) {
if( hasGamepadValue )
return gamepadValue;
else if( hasDesktopValue || isNonSpecific )
return desktopAndFallbackValue;
else
return mobileValue;
} else if( inputType == InputController.InputType.Touch ) {
if( hasMobileValue )
return mobileValue;
else if( hasDesktopValue || isNonSpecific )
return desktopAndFallbackValue;
else
return gamepadValue;
}
return desktopAndFallbackValue;
}
public static implicit operator float(PlatformFloat f)
{
return f.current;
}
public static implicit operator PlatformFloat(float f)
{
return new PlatformFloat {
presence = PlatformValuePresence.NonSpecific,
desktopAndFallbackValue = f
};
}
}
using UnityEditor;
using UnityEngine;
using System;
[CustomPropertyDrawer (typeof (PlatformFloat))]
public class PlatformFloatDrawer : PropertyDrawer
{
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
EditorGUI.BeginProperty (position, label, property);
var labelWidth = EditorGUIUtility.labelWidth;
EditorGUI.LabelField(new Rect(position.x, position.y, labelWidth, position.height), property.displayName);
var presenceProperty = property.FindPropertyRelative("presence");
var presence = (PlatformValuePresence) presenceProperty.intValue;
float x = labelWidth;
float contentWidth = position.width - labelWidth;
float dropdownWidth = 40;
float valuesWidth = contentWidth - dropdownWidth;
if( _popupStyle == null ) {
_popupStyle = new GUIStyle(EditorStyles.popup);
_popupStyle.margin.right = 0;
_popupStyle.fixedWidth = dropdownWidth;
}
var dropdownRect = new Rect(x + valuesWidth, position.y, dropdownWidth, position.height);
var newPresence = (PlatformValuePresence) EditorGUI.EnumFlagsField(dropdownRect, GUIContent.none, presence, _popupStyle);
if( newPresence != presence ) {
presenceProperty.intValue = (int) newPresence;
presence = newPresence;
}
bool hasDesktop = FlagsX.IsSet((int)presence, (int)PlatformValuePresence.Desktop);
bool hasGamepad = FlagsX.IsSet((int)presence, (int)PlatformValuePresence.Gamepad);
bool hasMobile = FlagsX.IsSet((int)presence, (int)PlatformValuePresence.Mobile);
int numVals = 0;
if( hasDesktop ) numVals++;
if( hasGamepad ) numVals++;
if( hasMobile ) numVals++;
// Using fallback "any" value?
bool isAny = false;
if( numVals == 0 ) {
isAny = true;
numVals = 1;
}
float singleValWidth = valuesWidth / numVals;
float iconWidth = 0;
if( !isAny ) {
iconWidth = 16;
if( _iconStyle == null ) {
_iconStyle = new GUIStyle(EditorStyles.label);
_iconStyle.padding = new RectOffset(0,0,0,0);
_iconStyle.margin = new RectOffset(0,0,0,0);
_iconStyle.fixedWidth = iconWidth;
}
if( _icons == null ) {
_icons = new GUIContent[3];
_icons[0] = EditorGUIUtility.IconContent("BuildSettings.Standalone.Small");
_icons[1] = EditorGUIUtility.IconContent("BuildSettings.PS4.Small");
_icons[2] = EditorGUIUtility.IconContent("BuildSettings.iPhone.Small");
}
}
if( _valueStyle == null )
_valueStyle = new GUIStyle(EditorStyles.numberField);
_valueStyle.fixedWidth = singleValWidth - iconWidth;
for(int i=0; i<3; i++) {
bool has;
string propertyName;
if( i == 0 ) {
has = hasDesktop || isAny; // desktop or fallback
propertyName = "desktopAndFallbackValue";
} else if( i == 1 ) {
has = hasGamepad;
propertyName = "gamepadValue";
} else {
has = hasMobile;
propertyName = "mobileValue";
}
if( has ) {
if( !isAny )
EditorGUI.LabelField(new Rect(x, position.y, iconWidth, position.height), _icons[i], _iconStyle);
var floatProp = property.FindPropertyRelative (propertyName);
floatProp.floatValue = EditorGUI.FloatField(new Rect(x+iconWidth, position.y, singleValWidth-iconWidth, position.height), floatProp.floatValue, _valueStyle);
x += singleValWidth;
}
}
EditorGUIUtility.labelWidth = 0;
EditorGUI.EndProperty();
}
static GUIStyle _popupStyle;
static GUIStyle _valueStyle;
static GUIStyle _iconStyle;
static GUIContent[] _icons;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment