Forum Replies Created
-
AuthorPosts
-
I apologize, the examples I have are kinda terrible and were made only for my own testing. There are classes within classes that are not necessary. My bad, I blame my own incompetence. Will try to add something more informative when I have time.
That said, my take on it is to put more emphasis on the data than on the code.
It may help to know that I want to design both the assets and the scenes themselves from within a 3D software (SideFX Houdini is the best candidate so far, but it can be Blender, Maya, etc.), export everything to FBX and Json files, and use M2 code to load and run the scenes, occasionally creating new components as M2 code and attaching said components to entities from within Houdini.
if it sounds too complicated, it isn’t: The assets are already being created in Houdini, so instancing them in a separate 3D scene and making a few scripts to export stuff out is the next logical step, and is actually a simpler pipeline (from an artist’s perspective) than doing everything in code.
As for the other question, “What’s the point of components”?… components are little bits of functionality added to entities. You can create complex behaviors by combining multiple small components (instead of subclassing and inheriting everything, OO style). For instance (not actual code!):
Entity “Dude”
| Component: “Transform”
| Component: “Sprite Render”
| Component: “Collider”
| Component: “Platformer Movement”
| Component: “Character stats”
| Component: “Player_Input”This is your main character. To make an enemy, simply make a new entity and add those components:
Entity “BadDude”
| Component: “Transform”
| Component: “Sprite Render”
| Component: “Collider”
| Component: “Platformer Movement”
| Component: “Character stats”
| Component: “Cause Damage to Stats on Collision”
| Component: “AI_Input”As you can see, we re-used a few components, but added a couple different ones. The “Platformer Movement” component always looks for an “Input” component, so in one case it is controlled by a human, on the other it is controlled by AI, yet the actual platforming (Jumping, colliding, etc.) is independent from where the input is coming from.
Which components are used can easily be defined in an external editor, and reloaded from the engine at any time, allowing quick testing and iterations.
Adam, I understand your stance, and certainly considered it in the past. But this approach feels right to me, and is actually quite popular in game engines these days. I also get to leverage my experience in film animation pipelines, where your data is your gold and all editing is done in 3D editors, which I’m very familiar with.
Hope that clarifies it for you even if you still don’t agree, which I totally respect
Cheers!Not sure how happy you’ll be about this (hopefully happy!) but I actually started on a component system for mojo3d
Very happy, considering everything I make by myself tends to be 178.3% slower and 451% more bug infested, on average.
It does mean I have to rewrite a bunch of stuff (again, since I had originally started something similar for Monkey-X!), but that’s Ok, I feel like I can probably add extra features on top of this and keep things cleaner that way.
I’ll definitely want to add serialization at some point. I was playing with bringing 3D models from Houdini today (for my game project, not included in the Github repo), and not recompiling every time I make a tiny change is way more pleasant!
Whatever you can do to make life easier in this regard is welcome, like always offering an optional New() constructor without arguments. The other thing I had to do on my system to make deserialization possible is being able to refer to objects by name. So Thing like Materials, Textures, GameObjects, Components, etc., can all be referred to by unique names, so you can set an Entity’s parent by name, for instance, or a material can refer to an existing texture by name, etc.
Or I can keep this stuff “on top” like it is now.
Cheers!I’d hate to see Monkey go.
I’m a veteran CG artist with an interest in programming, and have been using Monkey since its first iteration.I tried a lot of other solutions – Unity3D, Construct, Haxe, Nim, etc. – but Monkey was the only one that had the blend of simplicity, flexibility and usability “out-of-the-box” I wanted. It also offered the opportunity to deepen my programming knowledge in a somewhat friendly way, despite being rough around the edges.
I feel like Monkey2 is very close to find its footing, but in a reality filled with mature Game Engines and Middleware created by relatively large teams, I wonder what would it take to cross that threshold.
If I had to pick one, and only one, thing to work on before calling it quits, it would be an organized effort to “open up” the language to more developers. Mark has put an admirable effort into Monkey, but it’s too hard for a single person to compete in the current game/app development arena.
Cheers.
Thanks!
Tried collapsing the root and expanding it. Works fine with this:
"exclude":["*.buildv*","*products*"]
But does not like when I add files that start with dots, like this:
"exclude":["*.buildv*","*products*",".git"]
This initially works after I alt+tab, but if i collapse the root and expand again, all filters are ignored. I can alt+tab again and the filters are reapplied, but now all files in subfolders disappear.
Also tried with other macOS and Linux hidden files, like “.DS_Store”, and ran into the same problems.
Thanks!
<edit>
This works. I just can’t use the dot in the beginning of the filename…
"exclude":["*.buildv*","*products*","*DS*"]
But somehow this doesn’t work, and causes the same problems as before…
"exclude":["*.buildv*","*products*","*DS*","*git*"]
This kind of filtering is incredibly useful, but it’s not working well for me.
Behavior is kinda random… sometimes the filter is not applied until I switch away from ted2Go, then back. Sometimes the filter is applied when alt+tab switching, but all files under subfolders disappear.
I’m also confused with the explanation for the use of *. You say that *filter checks for text that starts with filter, but your example project.json file has the string *.products, which doesn’t seem to work. Shouldn’t it be .products* if you want to check for strings that end with .products? I mean, until regexp is supported.
Cheers.
Tested the latest dev branch for a few minutes, crash seems fixed now. Thanks!
Definitely crashing within a few seconds on MacOS. Seems to be related to the error hilighting since it happens as soon as I hover the error red line in the document.
I launched a debug build from the command line and got this (I removed any file paths in the error):
Attempt to invoke method on null instance
{{!DEBUG!}}
>?????:Void();/home/ … /Ted2Go/view/HintView.monkey2;33;533590191
>?????:Void();/home/… /monkey2/modules/std/time/timer.monkey2;38;530998829
period:Double=0.55555555555555558
timeout:Double=200.16928584955556
now:Double=200.17998897400003
sleep:Double=-0.010703124444461309Maybe I’m oversimplifying here, but isn’t it enough to create a text file in a folder where the main monkey file is, then just:
Monkey1#Import "myFolder/myFile.txt"From then on, simply use SaveString and LoadString with the file asset, like this:
Monkey1SaveString( myData, "asset::myFile.txt" )myFile.txt is copied to the build folder when you build the app, and “lives” with the app from now on, allowing persistent data to be saved and loaded. The original file is unaltered when the app saves the string, since it now saves over the copy in the build folder instead of the original.
(never tried it on mobile, but should work, shouldn’t it?)
Sweet! Works now.
I remember something about serialization not recognizing generics, and I definitely see it not working.It also fails on Enum types, apparently. The way I’m gonna work around it is having properties that return arrays or other values, instead of generic classes and structs, so that instead of:
Monkey12345Property Position:Vec3<Float>()Return _positionSetter( p:Vec3<Float> )_position = pEndI’ll do:
Monkey12345Property Position:Float[]()Return New Float[]( _position.X, _position.Y, _position.Z )Setter( p:Float[] )_position = New Vec3f( p[0], p[1], p[2] )EndOr I can create ToArray() and FromArray() method extensions to classes and structs I know I’ll use anyway, like Vec3f, etc.
Gonna work on loading now. Will post Serialize/Deserialize code to archives once it works well (I already have it handling arrays, yay!).
Monkey2 is a lot of fun. Cheers!
Thanks Mark!
Things are working nicely, but I’ve ran into a problem that may be more related to how inheritance works than to reflection… in the following code, I can’t serialize the objects coming from a stack with the correct extended type. They end up all being serialized as “BaseClass”, even though one of them is “ExtendedClass”.
Is there a way to cast them as i iterate through the stack?
Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293#Import "<std>"#Import "<reflection>"Using std..'************************ json extension '************************Class JsonObject ExtensionMethod Serialize( key:String, v:Variant )Select v.Type.NameCase "Double"SetNumber( key, Cast<Double>( v ) )Case "Float"SetNumber( key, Cast<Float>( v ) )Case "String"SetString( key, Cast<String>( v ) )Case "Bool"SetBool( key, Cast<Bool>( v ) )DefaultLocal newObj:= New JsonObjectnewObj.SetString( "Class", v.Type.Name )For Local decl:DeclInfo = Eachin v.Type.GetDecls()If ( decl.Kind = "Property" And decl.Settable )' Or ( decl.Kind = "Field" )newObj.Serialize( decl.Name, decl.Get( v ) )EndNextSetObject( key, newObj.ToObject() )EndEndEnd'************************ main function '************************Function Main()Local test1 := New BaseClass( "test1" )'This object will be reported as "BaseClass", instead of "ExtendedClass"Local test2 := New ExtendedClass( "test2", "Ni!" )Local json := New JsonObject()For Local t := Eachin BaseClass.All()json.Serialize( t.Name, t )Next'However this one, not coming from the stack, works!json.Serialize( "test3", New ExtendedClass( "test3", "NiNiNi!" ) )Print json.ToJson()End'************************ test classes '************************Class BaseClassProperty Name:String()Return _nameEndMethod New( name:String )_name = name_words= "Ekke Ekke Ekke Ekke Ptang Zoo Boing!"_all.Push( Self )EndFunction All:BaseClass[]()Return _all.ToArray()EndProtectedField _name:StringField _words:StringGlobal _all:= New Stack<BaseClass>EndClass ExtendedClass Extends BaseClassProperty Words:String()Return _wordsSetter( w:String )_words = wEndMethod New( name:String, words:String )Super.New( name )_words = wordsEndEndYeah, the chin ended up looking like a nose (and the double chin like the normal chin!), so it looks like he has a big nose and is sadly looking down…
Will fix when I find some time.
P.S. I hope you don’t mind us… monkeying…with your logo.
Found it. The property that wasn’t working returns a struct “NonsenseStruct”, but it sets a String property in that struct, instead of setting the struct itself.
Changing it to this works:Monkey1234567Property BrandNewName:NonsenseStruct()Return _nonsenseSetter( n:NonsenseStruct )_nonsense = nEndSo close! This code almost works with the latest dev branch. The goal is to print out all settable properties, recursively.
Only when we uncomment the “BrandNewName” property, which returns a struct, it fails. Can’t see why, since the Color property also returns a struct, yet that one works perfectly.Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113#Import "<std>"#Import "<mojo>"#Import "<reflection>"Using std..Using mojo..Class JsonObject ExtensionMethod Serialize( key:String, v:Variant )Select v.Type.NameCase "Double"SetNumber( key, Cast<Double>( v ) )Case "Float"SetNumber( key, Cast<Float>( v ) )Case "String"SetString( key, Cast<String>( v ) )Case "Bool"SetBool( key, Cast<Bool>( v ) )DefaultLocal newObj:= New JsonObjectnewObj.SetString( "Class", v.Type.Name )For Local decl:DeclInfo = Eachin v.Type.GetDecls()If decl.Kind = "Property" And decl.SettablenewObj.Serialize( decl.Name, decl.Get( v ) )EndNextSetObject( key, newObj.ToObject() )EndEndEndFunction Main()Local json := New JsonObject()json.Serialize( "text","Just a little text" )json.Serialize( "number", 100.0 )json.Serialize( "isItTrue?", False )json.Serialize( "Knight1", New KnightWhoSaysNi )json.Serialize( "Knight2", New KnightWhoSaysNi )json.Serialize( "KnightStruct", New NonsenseStruct )Print json.ToJson()End'***************** Test classes and structs *****************Class KnightWhoSaysNiPrivateField _name := "Ni!"Field _value:Float = 1000.0Field _schroob:= New SchruberryField _nonsense:= New NonsenseStructField _color := New Color( 0, 0, 1, 1 )PublicProperty Value:Float()Return _valueSetter( v:Float )_value = vEndProperty Name:String()Return _nameSetter( n:String )_name = nEndProperty Request:Schruberry()Return _schroobSetter( s:Schruberry )_schroob = sEnd'Uncomment these lines to get a scary error!' Property BrandNewName:NonsenseStruct()' Return _nonsense' Setter( n:String )' _nonsense.Words = n' EndProperty Color:Color()Return _colorSetter( c:Color )_color = cEndEndClass SchruberryProperty Random:Float()Return Rnd()Setter( bogus:Float )'One that looks nice. And not too expensive.EndEndStruct NonsenseStructPrivateField _words:= "Ekke Ekke Ekke Ekke Ptang Zoo Boing!"PublicProperty Words:String()Return _wordsSetter( w:String )_words = wEndEndThis will spit out the following string:
Monkey12345678910111213141516171819202122232425262728293031323334353637383940414243{"Knight1":{"Class":"default.KnightWhoSaysNi","Color":{"A":1,"B":1,"Class":"std.graphics.Color","G":0,"R":0},"Name":"Ni!","Request":{"Class":"default.Schruberry","Random":0.41015625},"Value":1000},"Knight2":{"Class":"default.KnightWhoSaysNi","Color":{"A":1,"B":1,"Class":"std.graphics.Color","G":0,"R":0},"Name":"Ni!","Request":{"Class":"default.Schruberry","Random":0.59253692626953125},"Value":1000},"KnightStruct":{"Class":"default.NonsenseStruct","Words":"Ekke Ekke Ekke Ekke Ptang Zoo Boing!"},"isItTrue?":true,"number":100,"text":"Just a little text"}Sorry for all the Monty Python references.
Managed to make a super quick cleanup monkey drawing… styling is still kinda “meh”, and I just went along with the same “monkey walking from the side” idea (again, super quick), but hopefully feels more clean and distinctive.

-
AuthorPosts