JM3: extend geometry / tell AssetManager what class to return?

ok, i can load an asset by – for example –



Spatial monster = assetManager.loadModel(“monsters/monster.mesh.xml”);



now i want to have a more generic class for all monsters, that is in fact derived from geometry. I scanned the src a little bit and found out that registerLoader() gives me the possibility to define a class by extension – nice! – but that would mean i have to give all monsters in my assets another extension. And – of course – even ‘Monster’ wolud not be the final class, because every type of Monster would get its own class. So … is there a better way to do this?



Something like… (pseudo-code!)



[java]

abstract class Monster extends Geometry implements AssetObject {…};



class Snoopy extends Monster {…};



getAssetManager().registerAssetObject(“Snoopy”);



Snoopy snoopy = (Snoopy) getAssetManager()



.loadClassModel(“Snoopy”, “monsters/snoopy.mesh.xml”);[/java]



In other words: Im looking for a way to tell the asset manager what class of object he has to construct. The alternative – having an object with a spatial private member – would mean i have to dublicate all functions, while a spatial public member would stop me from the possibillity of overriding some fn at need.

I suggest not extending Spatials or Geometry but using Controls, they can be attached to a Spatial and saved along with it.

Also consider using the userData map of Spatial if you want to add custom data to your geoms.

I was asking a similar question here (http://hub.jmonkeyengine.org/groups/general-2/forum/topic/loading-a-model-into-a-pre-existing-geometry/#post-123908) before I realized that there was a potential answer here from only a month ago.



At first I didn’t think there was a good answer here, but then I thought more about what nehon said. I realized that I could have some MyClass separate from its underlying Spatial and, when setting up an instance of MyClass, do model.setUserData(“blah”, this) then, where I had a reference to the model and needed to refer back to its backing MyClass, I could do Object o = getUserData(“blah”) then tell the MyClass to do what I want instead of telling the model to do what I wanted. In my case, o.click().



This is good enough for now, but I think it would be much better if we could add functionality to Spatials and/or their subtypes by extending them and telling the model loader either to use a pre-existing Spatial or create one of a type that is specified. Then we could set up something that didn’t seem like a hacky work-around.



Is this how everyone handles this issue if they are using models and need to refer to some object that actually has the game logic in it, keep the object separate and keep a reference to it in userData?

If you want you can let your extended class load userData or access a control and present it via methods. We don’t really want to support extending Spatial as new scenegraph members should only be created when there is a good reason for that, not just for storing data or creating game logic. Thats what userData and controls are for.

Actually I also work with extending spatials (mainly Nodes). Its probably the fastest and easiest method to use, but I must admit that it really isn’t what good java practices are about… What bothers me about putting things in control class is that I don’t like mixing creation of object visuals (I mainly create my objects in code :)) with its behaviour definitions. Also, picking for example returns geometry, so its kinda logical to receive back exactly what user picked with all its properties. Another thing, I hate endless Object casts for UserData. That could maybe be improved with generics?

You can access anything in the geometry via getControl(ControlClass.class); theres no real difference to a “normal” method. Also you don’t block yourself in extension trees… Imagine you have base movable, extend to vehicle and character, then suddenly you want to add a vehicle thats also a character… boom. That does not happen when you extend “flat” using controls. You can always consider a class a “movable” when it has a MovableControl and a Character when it has a CharacterControl, no extension lock-in.

I extend Node all the time… And I think I have an abstract class extending Geometry as well…



I’mma bad Monkey :cry:



Though, I did do a playerControl control that I can stick on anything with a CharacterControl… Trouble is that is a special node containing a CharacterControl… DOH I’MMA BAD BAD MONKEY :cry:



:epicsadfacemonkeysmiliethatdoesn’texist:

~FlaH

normen said:
We don't really want to support extending Spatial as new scenegraph members should only be created when there is a good reason for that, not just for storing data or creating game logic.

I think the reason some of us have different views of the optimal solution is due in part to project scale - those of us who are relatively new mostly have simple projects we are using as a testing ground to get a feel for jMonkey.

For simple projects, it actually makes sense to have one object contain everything concerning it: its scene graph components, its data, its game logic, and anything else it might have. If there is not a need to increase complexity, then it is best to avoid it.

However, I was thinking naively and not taking the bigger picture into account. Once I am done with this somewhat smallish project and start something more serious which has more complexities, I can see how I might easily fall prey to a host of various issues. The first one being that my objects were extending Geometry; that is fine for my cube/sphere placeholders but is not fine as soon as I have multiple Geometries for one object. I could extend Node for them instead, but that is only delaying the problem to the next bridge.

When I saw your first post about using Controls in this thread, I glanced over them very briefly, as they did not seem relevant to the issue I was having. I must have either misunderstood something or missed the point, seeing your further insistence on using them. I will go back and look at the purpose of your Control more carefully.

@InShadow: I agree that excessive casting gets annoying, however, when I find myself doing that I also tend to notice that I'm not making the best design decisions. If you find yourself doing a lot of that, try factoring out the things that are causing it. Or, if it is because your design demands that you just have to keep making use of something that requires it, you could at least abstract the data fetching out as a one-liner. For example, in my situation I wanted something that was Clickable, so instead of doing Clickable c = (Clickable)geometry.getUserData("clicky") a lot, I could instead do

`pre type="java"`
UtilClass

{

    public static Clickable getClickable(Geometry g)

    {

        return (Clickable)g.getUserData("clicky");

    }

}
`/pre`

Then whenever I wanted it I could just do Clickable c = UtilClass.getClickable(geometry) instead. Remember, it never hurts to factor something out into its own method for readability/maintainability. It's not going to hurt performance any even in a very tight loop because the compiler usually inlines it for you anyway.
1 Like

Glad to see informative exchange of opinions instead of mindless fights over how to create software here :slight_smile: Of course you can use jME3 in any way you please as long as you can live with the consequences :wink: But the metods we add and helpers we provide should together form a more or less concise concept for their usage. jME2 suffered very much from the attempts to combine too many options and systems under one hood thats why we try to play the “hardliners” here at least until jME3 is in its first release :slight_smile:

Cheers,

Normen

loduwijk said:
`pre type="java"`
UtilClass

{

    public static Clickable getClickable(Geometry g)

    {

        return (Clickable)g.getUserData("clicky");

    }

}
`/pre`


Another approach:

[java]
public class Util {
public static <T> T getUserData( Spatial s, String name ) {
return (T)s.getUserData(name);
}
}[/java]

...and never have to write a specific util method again. The compiler will determine type based on usage in 90% of cases... in the other rare cases you'd still have to cast.

...though as hinted by @inshadow, that generics trick could be added right into Spatial's getUserData() and then it casts for you.
1 Like

@loduwijk:



In my personal opinion, attaching UserData (model) to Spatial (visual representation) is not a good approach. If you want to change the game into 2D you would have to rewrite everything. Thats why i think its better to have Controls that manage control&data flow between Views (Spatial) and Model (some dataholder & data operation class) → In my game i have only some control bound to Spatials whatsoever (these that depend on spatials to operate, like CharacterControl, CameraControls)



So in your case: I would change geometry.getUserData(…) to geometry.getControl (MainControl.class).getUserData(…);

Hello… zomg!



I get it now!


pspeed said:

...and never have to write a specific util method again. The compiler will determine type based on usage in 90% of cases... in the other rare cases you'd still have to cast.

...though as hinted by @inshadow, that generics trick could be added right into Spatial's getUserData() and then it casts for you.


You guys are Sorcerers, mages, spellweavers or warlocks! NO WONDER WTFZZZ *Falls over still crying about being a bad programmer as before* :p

In other news, that sounds pretty awesome @pspeed. Going to check it out a bit later. Honestly, this topic reminded me completely about the whole userData concept within spatials. I'd totally forgotten, heh.

~FlaH
pspeed said:
Another approach:

public class Util {
public static <T> T getUserData( Spatial s, String name ) {
return (T)s.getUserData(name);
}
}

Wow, thats pretty awesome generics magic I have to say, I thought exactly that wasn't possible. Added to Spatial.getUserData in svn.

[java]public class Util {

@SuppressWarnings("unchecked")

public static <T> T getUserData( Spatial s, String name ) {

return (T)s.getUserData(name);

}

}[/java]

1 Like

The warning suppression should be unnecessary in this case since getUserData() returns Object. If getUserData() were generified (as it just was) then you’d have the issue… but then you also don’t need this utility anymore. :slight_smile:



And Spatial also shouldn’t need the suppression. The SpiderMonkey stuff where I did similar didn’t need it.

1 Like

I think casts are not meant to be used like this, but its a simple and effective trick… :slight_smile:

Oh btw check this: http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeParameters.html#Can%20I%20cast%20to%20the%20type%20that%20the%20type%20parameter%20stands%20for?

Yes, the suppression is necessary… when I added similar to the network session attributes, I mistakenly believed jme built with these warnings on. Though it’s just one warning in a whole deluge of type check warnings as it turns out. :slight_smile: