Nested Instantiable objects and intelligent mirroring

What would you like to see in future versions of the editor?
Post Reply
NauticalMile
Posts: 11
Joined: Wed Apr 09, 2014 1:56 am

Nested Instantiable objects and intelligent mirroring

Post by NauticalMile »

I have recently purchased the RUBE editor and I am loving it. Nevertheless I have the following requests:

Nested Instantiable Objects
Whenever instantaible objects are rolled out, I believe that man users (myself included) will eventually want to be able to nest them. For example consider two car objects who would like to refer to the same wheel object, or a tree object with several branch objects. This has been a high priority request from users of the Unity editor for years, and while the reason for not implementing it is not clear, the demand is definitely there.

All I ask is that whenever nested objects are rolled out, the door be left open for the possibility of nested instantiable objects.

Mirrored Instantiable Objects
The motivation for this request comes from my experience as a Computer Aided Design (CAD) software user. Whenever I was faced with making a mirrored version of a 3d part, I actually had to make a second part from scratch. There was no intelligent link between the two, and if you updated one part, you had to make the same change to the mirrored version. It was extremely tedious.

I know the ability to mirror selections in RUBE exists, but I was hoping that when instantiable objects arrive, they would gracefully incorporate a way to maintain a mirrored version of themselves.
iforce2d
Site Admin
Posts: 861
Joined: Sat Dec 22, 2012 7:20 pm

Re: Nested Instantiable objects and intelligent mirroring

Post by iforce2d »

Both good points, thanks for the feedback. I'm pretty sure these should be possible.

While I have your attention, maybe you could comment on a few other points about instantiable objects.

Currently you can get a reference to specific items after loading a scene into your own program by using functions like getXXXByName etc. I'm thinking that when exporting a scene with instantiated objects, each instance would have a name that would be prefixed to all bodies/joints/fixtures etc contained in that instance, with some special character as a separator. For example, the name of a body would become "instancename:bodyname", or perhaps "instancename/bodyname". An alternative would be to leave item names unchanged, and add an "instanceName" property to all items that came from an instance, and have a getXXXByInstanceAndName(instanceName, itemName) function instead. Having both of these available to choose from should not be a problem.

It might be useful to give objects some properties that could apply to all the member items, for example an instance could have a colorTint that would be used to augment the colorTint of all images in that instance when exported. There are probably quite a few others that could work (eg a modifier for density of all fixtures), with varying degrees of complexity and usefulness.

An object template could be an external file (another .rube file), or it could be made by selecting a set of bodies in the scene and declaring that they are now an object template. The external file method has the advantage that it can be shared across multiple scenes. The in-scene method has the advantage that updating instance displays would not require polling the template file for changes (only a small delay but could get kinda annoying after a while), and potentially all instances could be rendered in real-time while editing the object template. Eventually it would be nice to have both methods available, but whichever is easiest will probably be done first :)

I would also like to have the ability to 'break' an instance, that is, all the member items of the instance would become normal items in the scene, no longer connected to the template object.

If anyone has any thoughts about these or other related things I'd be glad to hear them.
NauticalMile
Posts: 11
Joined: Wed Apr 09, 2014 1:56 am

Re: Nested Instantiable objects and intelligent mirroring

Post by NauticalMile »

box2d Element Accesses
I have to confess I have not used the loader yet. I have just worked with the RUBE editor. I, personally, would like to load objects into my own data structures at the beginning of a level, and then release the loader until it's time to save or change scenes or something, so I don't have a strong preference between those two methods. I'm also using love framework for my game, so I (or another team member) will need to write a loader for love.

Object Instance Inheritance
As for the 'object modifiers' I think it would make more sense if the instances inherited all of the template's properties by default, but had the option to override some properties. I think the best way to set this up would be to have a 'modifiable' flag next to each property on the template which the user could set. E.g. I might allow modification of the density of a particular fixture for individual instances, but I might not allow the colorTint or other custom properties to be changed for specific instances.

External Files vs. In-scene Editing
I would vote for using external files first because it allows the user to use the object across multiple scenes. To me this is more valuable than the convenience of editing them in place (of course having both would be ideal). In general, I would almost always prefer more functionality over convenience, but that's just me. 8-)

Breaking Instances
Having the ability to break instances would be great as well. I think people would appreciate just using a template as a starting point from which to make new objects or other structures.
iforce2d
Site Admin
Posts: 861
Joined: Sat Dec 22, 2012 7:20 pm

Re: Nested Instantiable objects and intelligent mirroring

Post by iforce2d »

About loading the JSON, yes that's pretty much how it works. You can find all the details here: http://www.iforce2d.net/b2djson/
There seems to be some kind of loader for lua around, but it is set up for a different framework (Gideros mobile) so whether it would be useful to you is another question: https://bitbucket.org/BigWinston/girube

About instances inheriting properties of their template, I am thinking they would simply be complete copies with every property inherited. So for example if you have a robot with legs, you would not be able to override say, the density of the legs fixture in an instance. You could however give custom properties to the instance itself, since they will be items in their own right, eg. the instance as a whole could be given a property to say that this instance should have heavy legs. I guess some script could be used to change the density of all fixtures called 'leg' in the instance. This might be a little more overhead to set up initially, but it would make for a more modular system overall. For example, if the robot template was changed to have four legs instead of two, you would not need to go around all the instances and change them.

Yes, I think using external files will be the way to go, at least for the first iteration. About the editing 'in place' method, I see in your other post here that you mention about the results of patterning are 'dumb', and it's tedious to have to run the script again each time to generate copies from the original. I assume you are meaning things like the rim pieces of the soft wheels example. Things like that would be a great use of the 'in-place' template/instance style, because they don't really warrant making a whole separate file for. So I think eventually it would be nice to have both methods.
NauticalMile
Posts: 11
Joined: Wed Apr 09, 2014 1:56 am

Re: Nested Instantiable objects and intelligent mirroring

Post by NauticalMile »

About instances inheriting properties of their template, I am thinking they would simply be complete copies with every property inherited.
Does this mean that the exported .json files will also contain copies of the objects? I noticed the json files can get pretty big. Some small scenes I've created export json files that are around 18 KB in size, so I imagine that larger scenes will require a few hundred KB of data. Depending how many scenes your game has and the scale of the game, this may or may not be significant consumer of storage space on the player's device. Then there's also the issue of the time it takes to parse larger files. I don't know for sure, but this could increase level load times significantly. Maybe you can comment; have you ever experienced long load times when loading a RUBE-exported json?
iforce2d
Site Admin
Posts: 861
Joined: Sat Dec 22, 2012 7:20 pm

Re: Nested Instantiable objects and intelligent mirroring

Post by iforce2d »

Concerns about file size and processing time really depend on the available hardware resources, so it's a pretty subjective question. With some desktop games having demos of 2Gb or more these days, I'll assume you're talking about mobile devices.

In my experience, minifying the exported JSON can reduce it to about 50% of the normal file size, and then zipping that makes it about 10% of the original. Even with large levels, I'm pretty sure other resource types (images, audio) will remain the most significant portion of the app bundle.

As for speed, the file needs to be read one way or the other, and the only sure-fire way to speed it up significantly would be a binary format. Initially I was worried about long load times myself, and I intended to make a binary format export someday. However, with more real-world use I've decided it probably is not worth the effort.

So yes, the exported .json will contain copies of the objects, at least for the first iteration. This greatly simplifies things on the loader side since nothing needs to be changed, and people can start using scenes exported with instanced objects right away.

The alternative would be to have objects as references to an external file, along with a position, angle, scale, and a bunch of custom properties, and rewrite all the loaders to open multiple files and create instances, position them, and apply their custom properties. It might save a little on total file size, but I really doubt that the multiple file access and extra processing necessary would be faster than loading copies.

The other more major problem, is that applying a scale transform to a group of bodies and joints is not a trivial procedure. To do it properly requires adjusting joint anchors and axes, reversing vertex windings, flipping and re-positioning images, etc. Judging from the code doing this in RUBE, it would require about 1000 lines of code added to the loader, for C++ at least. I don't really feel like doing that for all the loaders, when the benefit is very small, and there is potential for human error to creep in to many places along the way.

Position and angle on the other hand, are not such a problem, so perhaps a future iteration could allow for instances that have a scale transform of 1,1 to be a reference to an external file.

As I mentioned in the other thread, instances will have custom properties for the instance as a whole, and probably some scripting could be done to adjust values in the member items, eg. to change the density of a fixture etc. If the exported scene contained objects as references to external files, this kind of adjustment would somehow have to be done after loading (again having this written into each loader version), and it would need to have some extra JSON structure to store what needs changing, and I think things would start to get really messy.

Finally, I'd like to keep the player view as close as possible to the actual scene that will be replicated by the loaders. The way RUBE works is, when you hit Ctrl+R to open or reload a player view, the scene is exported to JSON (in memory, not to file) and then the player view uses standard b2dJson code to load it. This means that what you see in the player view should be exactly what you get when you load the scene into your own game. If each loader was to be doing a bunch of post-load processing to set up object instances, the chances of keeping a 1:1 result faithful to the player view start to deteriorate.
NauticalMile
Posts: 11
Joined: Wed Apr 09, 2014 1:56 am

Re: Nested Instantiable objects and intelligent mirroring

Post by NauticalMile »

Hi iforce,

I just watched your newest video concerning the new RUBE 1.7.1 update. My build is queued and I'm excited to try it out!

I've done enough programming to know that implementing nested instanciable objects would be no easy task, which is why I really appreciate that you've gone the extra mile to make it happen. The system already seems pretty robust from what you've demonstrated, and looks suitable for a lot of different projects.

I'm also kind of delighted that the next problem you've come across is how to manage joint relationships between parent and child objects. It just so happens I've written a lengthy answer on the topic with respect to game entities over here.

The gist of my thoughts are that it is the responsibility of the parent object (in this case the parent RUBE file) to keep a set of references to the anchor points which are defined within the child object(s). Consider this example:

Wheel:
  • Wheel body centered @(0,0)
    • Anchor point @ (0,0) named "mount"
Car Frame:
  • Car frame body centered at (0,0)
    • Anchor point @ (1,-0.5) named "frontAxle"
    • Anchor point @ (-1,-0.5) named "rearAxle"
Basic Car:
  • Instance of Car Frame named "carFrame"
  • Instance of Wheel named "frontWheel"
  • Instance of Wheel named "rearWheel"
  • Joint List:
    • Revolute Joint connecting a point called "mount" within the object called "frontWheel" to a point called "frontAxle" on an object called "carFrame"
    • Revolute Joint connecting a point called "mount" within the object called "rearWheel" to a point called "rearAxle" on an object called "carFrame"
When you export/play, you just need to find the references defined in the joint list and their associated bodies. Then, construct the joints. When there is a missing reference, it just needs to be identified (possibly when you do that routine check on the child components every 5 seconds), and you can signal the user in some way to let them know that one or more of the references is no longer valid. I've got something similar working pretty well in my current game project (not the editor of course, it just builds objects from their definitions in files), and while there are a couple of wrinkles in the creation routines because of this, it's pretty straight forward to create nested objects.

I hope that, if anything, I've helped you think about the problem in a different way, even if you end up going in a totally different direction. Best of luck!
iforce2d
Site Admin
Posts: 861
Joined: Sat Dec 22, 2012 7:20 pm

Re: Nested Instantiable objects and intelligent mirroring

Post by iforce2d »

Yes, the relation of objects and mount points would need to be done pretty much exactly as you say. What concerns me more than this though, is the user interface that allows it all to be set up. It could easily become very confusing if not handled nicely.

Presumably we'll need a new item type (and a new editing mode and script class to go with it) for creating, placing, and naming the mount points. Adding a new item type takes about two days but is not too hard. In the referencing scene though, we will want to be able to edit joints as easily as we already do, retaining as much similar GUI as possible. Joints would need a major restructuring so that instead of connecting two bodies, they connect an abstract thing which may still be a concrete body in the scene, or it may be a body referenced via a mount point.

Re-targeting an existing joint to connect mount points could be done by clicking the buttons for Body A and Body B in the properties panel, and the mode which currently presents only bodies for selection could also recursively descend into all object instances to show their mount points for picking. Coincident mount points will be rather a nuisance here.

Adding a new joint from scratch could perhaps be done by selecting a body/mountpoint pair and then adding a joint in the usual way. For body/body and mountpoint/mountpoint connections this should be fine, but it could be confusing for body vs mountpoint connections, because only one of these will be visible, depending on which edit mode is active.

After all that is sorted out, there is the code to transform and construct all this... I'm guessing overall it's about as much work as adding instanciable objects in the first place, which is why I am not the least bit surprised that Unity does not support this kind of stuff. I'm also kinda wondering about how many users would actually make use of it, since it will mainly be useful for quite complex hierarchies.

So, given the amount of work involved vs the payoff, and the trampling on existing code it would require, is why I decided to draw the line for the time being, and see how it goes with this 'basic' instanciation, which hopefully is still a pretty good step forward. At this point I will add "joints between object instances" to the feature voting, and focus for a while on other features that have relatively high votes.
NauticalMile
Posts: 11
Joined: Wed Apr 09, 2014 1:56 am

Re: Nested Instantiable objects and intelligent mirroring

Post by NauticalMile »

iforce2d wrote:At this point I will add "joints between object instances" to the feature voting, and focus for a while on other features that have relatively high votes.
Given the user interface issues you have described, this seems like a very good decision. I think it's also probably a good idea to let the existing RUBE users become familiar with instantiable objects for a time before any more complexities are introduced.

After playing with it a little yesterday, I've started thinking of a couple of ways I can implement some sort of primitive system using scripts to update joint references of objects. I'll share some rubescripts if I get something reasonable working.

Thanks Again for all your hard work!
Post Reply