Reflecting on reflection. Game maps and plugins.
August 7, 2017 at 5:33 am #9755
I have been experimenting with Monkey2’s Reflection in an attempt to use it (along with parsing source files) to add game map and plugin support to my Alien Phoenix project. Before I get to deep into this subject I thought posing a few questions might help me understand what Reflection is best suited for and what limitations/pitfalls I might encounter.
So, what is a best use case for Reflection? Is a game map or plugin system (source files parsed and processed) suited to use of Reflection? What issues are going to be limitations or pitfalls when using Reflection in a setting designed to support game maps and plugins.
Reflection looks interesting and a possible candidate to add game map and plugin support to my Alien Phoenix project. If you can offer some advice please feel free to let me know what you think.August 7, 2017 at 5:48 am #9757
I think, you can’t just write new source code and dynamically load it via reflection – recompile code is required.
If your plugins will use standard lang features, then you can (probably) use it like lua-scripts works.
This time reflection doesn’t work with generic types (core vec2/3/4 and rect are generic).August 7, 2017 at 10:46 am #9759
Reflection appeals to me in that when parsing script (more like source code in this case) I can easily invoke a method or function that is exposed to Reflection. This includes all of the public portions of my code as well as included modules and source imports. I have tinkered with scripting a bit and chose to use a contained variable approach where the variables are always included between parentheses even when initializing a variable. Something like myrect:= New Rect becomes CreateRect(Name) in script. This approach makes parsing (I guess tokenizing as well) easy and as long as I have a corresponding method or function ( like CreateRect() ) and handling generic types like Vec2() can be accommodated. In Vec2()’s case I would expect to use Vec2(var-name, va1, var2) in script where var-name is the invoked type (rect for example).
The downside is features like For/Next loops or adding, subtracting become difficult and more complex to implement. In the case of addition something like Add(var-name,var,var) where var-name is receiving the product of the addition. For loops like For/Next something like this script might work:12345678CreateInt(my-int)CreateInt(myadd1-int)CreateInt(my-var-int)Value(myadd1, 10) 'variable equals variableLoopStart(my-int, 1, 100) ' variable name and then iteration variables.Add(my-var-int, my-var-int, myadd1-int)LoopEnd()
This simple script illustrates my interest in Reflection and why I think it could be useful for scripting. The potential for easy parsing and processing of script using Reflection seems to me to be possible. Combined with an easy to learn and use scripting language I can imagine Reflection making the above possible.August 7, 2017 at 11:25 pm #9762
I have faced a practical use case with reflection in C#, to have the runtime system read the static type system and make some creative uses out of it, for example one real benefit is to avoid silly boilerplate code and gain some dynamism in this side.
For example if you have this:1234interface IExample ...class FirstExample : IExample ...class SecondExample : IExample ...class ThirdExample : IExample ...
You can iterate the class names (that implement the interface) and store them to a string list, and present them to the user, once you enter the name of the class you want, you can search the class by name and initialize it right away. This technique is used in some programming frameworks where having to manually maintain the descriptions of 100 examples is not a wise choice. 🙂August 10, 2017 at 2:48 pm #9778
I have been working on a scripting framework and at this point in Reflection’s development I’m thinking it’s just easier to encapsulate class types into a separate class (‘s). In addition to nonsupport of generic types there are some other issues for example this is not supported in reflection.1234Add(var1:Int, var2:Int)Add(var1:Float, var2:Float)Add(var1:String var2:String)
The absence of generic type support leads to abstracts which support the script. This makes it difficult to support a user type and requires a lot of overhead. I’m still experimenting and I’ll be posting what I come up with, but it’s looking like Reflection at present is a less then perfect option runtime wise.August 12, 2017 at 4:38 pm #9797
If Monkey treated datatypes as objects you would do this:123456Function Add(a:Object, b:Object)EndFunction Main()Add(10, 10.0)End
But now you might try this:1234567891011121314151617181920212223Class AddOperationPublicFunction Add:Variant(a:Variant, b:Variant)' if a is int and b is int thenReturn Add(Cast<Int>(a), Cast<Int>(b))' endReturn NullEndPrivateFunction Add:Int(a:Int, b:Int)Return a + bEndEndFunction Main()Print(AddOperation.Add(10, 10))End
However if is possible to automate anything Reflection I would be interested to learn how is done. 🙂August 14, 2017 at 3:25 am #9807
If there is finite number of data types to create then you can write data parser w/o reflection.
Your own declarative lang 🙂 that will use needed internal functions.12345CreatePlayer 10,0,0Loop 10CreateEnemy Rand(20),Rand(20),Rand(20)End...
Each string token produce its action – CreatePlayer return instance of Player and set coord for him and so on.August 14, 2017 at 9:24 pm #9823
For example if I have this simple example, can I use reflection to bypass the Select statement?123456789101112131415161718192021222324252627282930313233343536373839#Import "<std>"Using std..Global script := New String("CreatePlayer", "CreateEnemies", "Loop")Class EntityField Name:StringMethod New(name:String)Name = nameEndEndFunction Main()Local entities := New List<Entity>Print("Starting script.")For Local s := Eachin scriptSelect sCase "CreatePlayer"Print("Creating a player.")entities.Add(New Entity("Player"))Case "CreateEnemies"For Local i := 1 Until 10Print("Creating an enemy.")entities.Add(New Entity("Enemy " + i))NextCase "Loop"Print("Updating the game.")For Local loop := 0 To 10' doing the normal game loopNextEndEndPrint("Script ended.")End
Note that this is the most simple example you can get, writing a full interpreter will need more work.
You must be logged in to reply to this topic.