Show field based on multiple enum values - Odin - c#

I want to Show the field in UnityInspector based on specific enum field.
Lets say this is the enum class
public enum Mode
{
None,
Movement,
Rotation,
Scale
}
I want to enable this field if "Movement or Scale" is selected from the enum dropdown, otherwise hide the field.
public Vector3 NewValues;
With Odin I can do:
[ShowIf("tweenMode", TweenMode.Movement)]
public Vector3 NewValues;
But that will work only on Movement enum. Any idea on how to make it work on multiple enums? Thanks

Afaik you can simply do something like
private bool showNewValues => tweenMode == TweenMode.Movement || tweenMode == TweenMode.Rotation;
[ShowIf(nameof(showNewValues))]
public Vector3 NewValues;
See ShowIf

You can use a property like mentioned before. You can also make use of Odin's attribute expressions which where added in version 2.1.0.0
[ShowIf("#tweenMode == TweenMode.Movement || tweenMode == TweenMode.Rotation")]
public Vector3 NewValues;
If you consider that easier / more readable is up to you, but it's another option.

Related

C#: default value for Vector in constructor

I have the following problem:
I have a classs that takes a position as a Vector2 in its constructor. Now, in some cases I don't know the position and want to change it at another place in the code. Since you can't make a Vector2 = null in C#, is there any default value for a Vector2 to signalize: "This Vector has no Value"?
This is the constructor in question:
public SoundEvent(SoundEffects sound, Vector2 soundOrigin)
I want to be able to call this constructor either with the SoundEffect only, or with the SoundEffect and position.
This is a better way:
public SoundEvent(SoundEffects sound, Vector2? soundOrigin = null)
Vector2 so;
if (soundOrigin == null)
so = new Vector2(); // default to origin?
else
so = soundOrigin;
The extra variable so guarantees null uses will not throw errors later.
Nullable<Vector2> is what I was looking for.

Can I assign an enum based on an array of strings?

I have a struct for a game I am building that looks like this:
using System;
public readonly struct Target
{
public Target((int Min, int Max) range, string[] targetTypes)
{
Range = range;
TargetType = ParseTypes(targetTypes);
}
public (int Min, int Max) Range { get; }
public TargetTypes TargetType { get; }
[Flags]
public enum TargetTypes { None = 0, Self = 1, Enemy = 2, Player = 4, Character = 8, Area = 16 }
}
I would like to take all of the values in the string array and cast them into a single enum (not an array of enum values, which I believe is what is happening in the answer to this question).
The thing is a Target can have multiple types. I figured an enum was the best way to represent this, and also figured defining the enum inside the struct wasn't a terrible idea, but this could be an anti-pattern (coming from a JS background, be gentle!).
I like this whole enumeration types as bit flags thing, hence the numbering, that's what sent me down this path.
Yes, I control the inputs, so happy to hear why/how I should do this differently - thanks for your time!
You could use the following.
TargetType = (TargetTypes)Enum.Parse(typeof(TargetTypes),string.Join(",",targetTypes));
The second parameter of Enum.Parse accepts either a single value/constant representing the enum or a list of named constants or underlying values delimited by commas (,).
Thank you #asawyer for pointing the way. I missed an important part of the documentation (always RFTM twice!):
Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object.
There's no need for anything fancy here, Parse does the trick:
TargetType = (TargetTypes) Enum.Parse(typeof(TargetTypes), string.Join(",", targetTypes));

Splitter value as interval for retrieving label?

I'm learning C# and Unity3D for a few months and now I stumbled on a logic, which hopefully somebody can describe to me.
(I already googled for hours and even looked up if other languages use enums that way.)
This code is from a free asset from the unity asset store, which I try to anatomize.
Everything is fine and understandable for me, but then it comes to the functions GetSliderData() and SetSliderData().
My Question: How does the modulo part works?
Why dividing anyway, when it comes to getting and setting values? Or is it some kind of syntax, like the lambda expression "=>" which is not ">="(less or equal sign)
Thank you in advance for your time!
Dom
public class SliderData : ScriptableObject
{
// Data storage
public List<float> sliderData;
/* Use a single enum as retrieval label for any slider by using a splitter
* value as interval. */
private const int ENUM_INTERVAL = 16;
public enum SliderField
{
// Customizer sliders
DEPTH_MIN,
DEPTH_MAX,
PERLIN_SPEED,
PERLIN_LEVEL,
ZONE_PERLIN_SPEED,
ZONE_PERLIN_LEVEL,
MAP_PERLIN_SPEED,
MAP_PERLIN_LEVEL,
}
/// Retrieves the value of the slider belonging to the given field constant.
public float GetSliderData(SliderField field)
{
return sliderData[(int)field % ENUM_INTERVAL];
}
/// Sets the value of the slider belonging to the given field constant.
public void SetSliderData(SliderField field, float value)
{
sliderData[(int)field % ENUM_INTERVAL] = value;
}
}
The % seems to have the purpose of wrap-around the given field value onto the existing indices of the sliderData list.
If the value reaches/exceeds the ENUM_INTERVAL it will instead start over from 0.
For your methods indeed this seems a bit redundant if using the enum values since there are only 8 of them anyway. But it could be triggered via type casting e.g. (SliderField)17 .. but why would someone do that?
Anyway this seems to simply assume that the sliderData list contains at least 16 elements ...
In general to be honest I wouldn't use such a structure but rather store and access the values via actual fields instead of this kind of "dictionary" List.
Ofcourse depends on the use-case and how exactly your asset is used later. It seems there is some behavior involved you didn't share here.
But instead of going through the magic enum and list indices - why not simply have
public class SliderData : ScriptableObject
{
public float DEPTH_MIN;
public float DEPTH_MAX;
public float PERLIN_SPEED;
public float PERLIN_LEVEL;
public float ZONE_PERLIN_SPEED;
public float ZONE_PERLIN_LEVEL;
public float MAP_PERLIN_SPEED;
public float MAP_PERLIN_LEVEL;
}

comparing two identical objects return false in Unity 3D (c#)

I am writing a C# script on Unity 3D. I have two Vector3 that are the same. When I do:
Debug.Log(vect1);
Debug.Log(vect2);
I get the same result (500.0, 150.0, 0.0). The problem is that when I do vect1.Equals(vect2) I get false! How is it possible?
P.S.
I am sure that they are both Vector3 because when I do vect1.GetType() and vect2.GetType() I always get Vector3.
Despite being a struct, Vector3 implements Equals via identity comparison. In other words, vect1 will only equal vect2 if they are the same instance.
However, Vector3 does implement == to test for value equality, so use that instead.
See https://msdn.microsoft.com/en-us/library/vstudio/ms128863%28v=vs.90%29.aspx for details.
Vector3 overrides the == operator to "return true for vectors that are really close to being equal". Since you may have some imperceptible differences in your floating-point values you might try using == instead:
vect1 == vect2
Here is why you could see what happens
Vector3 v1 = new Vector3(150.001f, 150.002f, 150.003f);
Vector3 v2 = new Vector3(150.002f, 150.003f, 150.004f);
Debug.Log(v1);
Debug.Log(v2);
Debug.Log(v1 == v2);
Debug.Log(v1.Equals(v2));
Debug.Log(Vector3.Distance(v1, v2) > 1e-3f);
This will print out
(150.0, 150.0, 150.0)
(150.0, 150.0, 150.0)
False
False
True
The issue is that your definition of close enough may be different from unity's. You can check that by using this function
public static bool AlmostEqual(Vector3 v1, Vector3 v2, float tolerance)
{
return Mathf.Abs(Vector3.Distance(v1, v2)) <= tolerance;
}
Hi guys I tell you how I solved the problem so far. I have made a member to member comparison.
int vect1x=(int)vect1.x;
int vect1y=(int)vect1.y;
int vect1z=(int)vect1.z;
int vect2x=(int)vect2.x;
int vect2y=(int)vect2.y;
int vect2z=(int)vect2.z;
Debug.Log((vect1x==vect2x)&&(vect1y==vect2y)&&(vect1z==vect2z));
I know that it's verbose but at least it works cause it's a simple comparison between integers...

XNA's Vector2 class, property returns an error when attempting to change its value

I will first illustrate my issue with some code:
class ExampleClass
{
private Vector2 _myVector;
public Vector2 MyVectorProperty { get { return _myVector; } set { _myVector = value; } }
private void MyMethod()
{
_myVector = Vector2.Zero; // Setting to zero
MyVectorProperty.X = 5; //Cannot modify the expression because it is not a variable (returns an error)
_myVector.X = 5; //Works fine!
}
}
As you can see, I am getting the error "Cannot modify the expression because it is not a variable" when trying to change the value of X and Y on the vector using the property. I am unsure why this happens and haven't had any luck looking on the net and i was wondering why this is and how (if) I can fix it?
Another sub question, is it good programming practice to use the public properties or the private/protected fields when working inside the class they belong to?
You should be happy compiler does not let you do so, otherwise you'll be really surprised with result of operation being lost.
MyVectorProperty is property - which means getting the value is call to a function returning the value (something like this.get_MyVectorProperty()).
Since type of the MyVectorProperty is Vector2 which is struct it means that value returned by the get_... function is a copy of value, not reference like it would be in case of normal class.
Changing field X of above copy would simply change X inside of copy of the value, and since that copy of the value is not assigned to anything it will be lost.
Vector2 is a struct (value type), so your property returns the value of _myVector (i.e. a copy) and you can't change that.

Categories

Resources