Jump to content
  • Advertisement
Sign in to follow this  
marvel_magnum

Unity Reflection problem in C#

This topic is 1334 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am writing a small game in Unity3D. There are special effects for the units in the game which take effect and are customizable. 
 
I have written a custom script so that the effects can be created on the fly through a data fly. 
Eg. The below script creates a buffID "Naptha" which give all archers in the player's army a fire arrow; fire damage is 15% of the base attack value.
 
[source]
#buff Naptha
{
         mod(SELF,[ARCHER],SpecialType = FIRE)
         mod(SELF,[ARCHER],SpecialDamage = AttackDamage * 0.15)
}
#end
[/source]
 
 
A parser parses the file into recognizable tokens. 
All the stuff in CAPS are enum types. and SpecialDamageAttackDamage are float properties of the Unit Class among others. Now the idea is to collect the values from the specified properties using reflection, calculate them and then feed back the result. 
 
Now I can extract the value of a property like so --
[source]object value1 = testUnit.GetType().GetProperty("AttackDamage").GetGetMethod().Invoke(testUnit, null);[/source]
 
I can even get the type of the property like so --
[source]Type baseStatType = testUnit.GetType().GetProperty("AttackDamage").PropertyType[/source]
 
Here come my problem. I cannot perform calculations with object types and I am not able to cast it to a type first as even the type is determined through reflection. How to proceed with this ?
 
Basically I want something like this to work ---
 
[source]
Type baseStatType = testUnit.GetType().GetProperty("AttackDamage").PropertyType
object value2 = testUnit.GetType().GetProperty("AttackDamage").GetGetMethod().Invoke(testUnit, null)
baseStatType value1 = (baseStatType) value2 * (baseStatType) param;
 
PropertyInfo result = testUnit.GetType().GetProperty("SpecialDamage");
result.SetValue(testUnit, value1, null);
[/source]
The other way I can think of (but dont want to do) is a dirty switch case based on the propertyname. sad.png
Edited by Marvel Magnum

Share this post


Link to post
Share on other sites
Advertisement

What about "dynamic"?

object a = 10;
object b = 0.5f;
dynamic c = (dynamic)a * (dynamic)b;
object result = c;

This will "just work", even when a and b are more complex types with custom multiplication operators, because the CLR will do at runtime what the normal compiler would have done at compile-time. It will even optimize it for you during the first invocation. However, I have never used Unity and have no idea if that feature of C# is supported.

 

The alternatives would be to either re-implement C#'s entire type system or to restrict your scripts to a few well-known type and do a switch on these. Do you really intend to use any types besides float, int and enums in these scripts?

Share this post


Link to post
Share on other sites
You can implement 'dynamic' using the old ways:
 
if (someObject is float)
{
    float value = (float)someObject;
    // do stuff with it.
}
else if (someObject is YourEnumType)
{
    YourEnumType value = (YourEnumType)someObject;
    // do stuff with it.
}

Or a Dictionary<Type,Action<object>>:

table[typeof(float)] = FunctionFloat;
table[typeof(YourEnumType)] = FunctionYourEnumType;

void FunctionFloat(object o)
{
    var value = (float)o;
    // do stuff
}

void FunctionYourEnumType(object o)
{
   var value = (YourEnumType)o;
   // do stuff
}

And call it with:

table[someObject.GetType()](someObject);

Obviously this gets out of hand quite quickly. Edited by Nypyren

Share this post


Link to post
Share on other sites

To expand on ferrous' reply, I would probably just convert all your values to a common type (Single, Double, etc.) for the purpose of performing calculations, then then convert the result back to the proper result type when finished.

Share this post


Link to post
Share on other sites

Is there any reason you can't just cast the stat value from object to float when you're performing the arithmetic?

 

I cannot because I would not know the actual type of the stat that has been read in.

 

 

 


Dictionary<Type,Action<object>>:

table[typeof(float)] = FunctionFloat;
table[typeof(YourEnumType)] = FunctionYourEnumType;

void FunctionFloat(object o)
{
var value = (float)o;
// do stuff
}

void FunctionYourEnumType(object o)
{
var value = (YourEnumType)o;
// do stuff
}

And call it with:

table[someObject.GetType()](someObject);

 

 

This should work for me. I have int, float and 3 types of enums among all my stats so it should be manageable.

 

Even Jeff's suggestion should work for me. 

 

 

 


Multiply<T>(T, T) through reflection.

 

I need to get down to the board and find out which one seems better. Will post solution soon. Thanks a lot guys. smile.png

Edited by Marvel Magnum

Share this post


Link to post
Share on other sites

This is how I did it in the end. Comments and suggestions are welcome as usual. :)

 

[source]
_operationMap = new Dictionary<Type, Delegate.dlgOperation>();
_operationMap.Add(typeof(float), OperationFloat);
...
 
// Snippet from method where effects are getting applied....
...
foreach (Unit unit in targetUnits)
{
    object op1 = unit.GetType().GetProperty(modifier.effect.baseStat).GetGetMethod().Invoke(unit, null);
    object op2 = modifier.effect.value;
 
    PropertyInfo result = unit.GetType().GetProperty(modifier.effect.resultStat);
    object retValue = _operationMap[op1.GetType()](op1, op2, modifier.effect.operation);
    result.SetValue(unit, retValue, null);
}
...
 
// One of the handler functions
private object OperationFloat(object op1, object op2, BuffsDatabase.Operation operation)
{
   float o1 = (float)op1; 
   float o2 = float.Parse(op2 as String);
   float result = 0f;
 
   switch (operation)
   {
        case BuffsDatabase.Operation.ASSIGN: result = o2; break;
        case BuffsDatabase.Operation.ADD: result = o1 + o2; break;
        case BuffsDatabase.Operation.MULTIPLY: result = o1 * o2; break;
        default: DebugUtils.Error("ERROR: Invalid Operation encountered in OperationFloat()!"); break;
    }
 
    return result as object;
}
[/source]
 
 
Thing works like a charm now.. Thanks for all your help guys. Love ya! 

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
  • Advertisement
  • Popular Tags

  • Popular Now

  • Advertisement
  • Similar Content

    • By Aryndon
      Project Redemption is an semi-fantasy RPG with a linear story and an elaborate combat system.
      We are building in Unity and are currently looking animators and artists.
      What we are looking for
      -Someone who is okay with split revenue/profits when finished
      -Collaborate with others in the team. Do you have an idea/thought on what should be included? Tell us!
      -Someone who wants to work with people that are passionate about this project
      If you are interested. Please message me and I will get back to you as soon as possible! Or add me on Discord AJ#6664
    • By Aggrojag
      Hello!
      I'm working on a game that is a narrative driven dark comedy with some small aspects of platforming and puzzle solving. The project is rather small as well. It touches on topics such as suicide, mental illness, family, corruption, free-will, and redemption.
      This project is exercise in polish, this means some experimentation will be needed along with some reworking of assets as they're provided.
      This will be a revshare model.
      First, I'm looking for a 2D sprite artist, not pixelated, that can compliment the style of the attached images, and be similar to the temporary character.
      We are looking to bring on a SFX designer at this time. Full list of required SFX will be available upon request, as well as a build with all elements related to sound implemented in some form (many SFXs pulled from the web for now). Will likely require some field recording, and some pretty strange SFX for when things get weird. I imagine a good portion of these will be quite fun to create.
      Lastly, I'm looking for a male voice actor, English should be your primary language. There will be at minimum two characters that will need to be brought to life through vocals. The first voice is similar to Marvin from Hitchhiker's Guide to the Galaxy. A reference for the second voice would be a mix of Ren (Ren & Stimpy), and Android 21 (DragonBallFighterZ). Due to formatting, I'm not including YouTube links in the post, sorry.
       
      WIP Scene with our custom shaders attached (platforms are lazily placed, as this was an asset test):

      A scene with dynamic lighting and temp character:

       
      Unshaded asset:

      If you made it to the bottom, thank you, and I look forward to hearing from you.
    • By SickTwistGames
      Ok, firstly, Hi.
       
      This is my first post on this forum. I am an Indie Dev making my first game so bear with me when I say dumb stuff, I'm on a huge learning curve.
       
      My first question is about inventory systems for unity. I am trying to make a survival type game with crafting. I have purchased Inventory manager pro by devdog from the unity asset store and it seems like a pretty powerful assett but for an intermediate coder its a little tough to use.  I'm beginning to wonder if it was the right purchase.
      So my question is.... does anyone have any experience of inventory plugins / systems for unity and can anyone reccomend a system to me?
      It needs to have the following: Loot system, crafting system, character sheet, blueprint system,  character stats system. Ideally with as little coding as possible.
       
      Thanks
    • By ethancodes
      I've got a bug with my brick breaker style game. The bricks move down one line at a time ever 1.5 seconds. What appears to be happening is occasionally the ball will be just about to hit the brick when the brick moves down a line, and now the ball is behind it. I'm not sure how to fix this. I have two ideas but I'm not sure of implementation. 1 solution would be to check where they were and where they are going to be before rendering the frame. Then if they crossed paths, then register the brick as hit. Solution 2 would be change how the bricks move. I could maybe slide them down line by line, instead of a jump down. I'm not sure of this will fix the issue or not. Any ideas?
    • By Pixeye
      I wrote an extension for unity inspector that allows to group/fold variables. 
      Available on github  , cheers!

       
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!