Cast spatial to geometry?

While my problem is a bit more complicated, the easiest possible solution would be to cast a spatial ( a newly loaded model) to a geometry so I could treat it as a geometry moving forward.

Searching on the topic turns up lots of posts that suggest a standard cast:

Geometry geo = (Geometry) spatial;

However while an app doing so looks fine in the sdk, running it causes an error to the effect of “spatial cannot be cast to geometry”.

I’m wondering now if it’s actually possible or do I need to find a different solution to my actual problem?

Thanks in advance.

Look through this, it might explain the concepts: https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:scenegraph_for_dummies

Not every spatial is a geometry (they can be nodes also) so you can’t just cast whatever spatial you find to a geometry. Spatials form a tree and you need to walk the tree to find the actual geometry you are interested in.

Cheers! that answers the question above.

It was good to read that guide again, but doesn’t actually solve my problem :slight_smile:

The problem I’m having is that I’m using the picking method given in jmonkeyengine3 for beginners, which shoots a ray and returns the first geometry on the line. This allows using target.getName() to find which one has been picked. This worked great with cubes (geometries)

But as I moved on through the project that the book has you do, it tells you to swap the objects for actual models using assetManager.loadModel() which also works great, until I realized that the picking was now failing because loadModel() returns a spatial, not a geometry and spatial.setName() effects the spatial while the picking is returning an underlying, separate geometry object which has the name of the mesh, not the one I’ve set.

spatial.getParent().getName()?

1 Like
@AndyLion said: It was good to read that guide again, but doesn't actually solve my problem :)

But it does provide the proper background to solving your problem which feels like might have been missed. Your loaded model is a node with (perhaps many) children of various configurations. So your code will need to be adaptable to this hierarchy as you are picking geometry.

As Normen suggests, you will need to identify the root in some way… either by traversing up the getParent() chain and checking for a specific name or by attaching a control or setting some UserData marker that you can find. Either way, getParent() is your friend here.

That got it!

I am a little embarrassed to say I tried that already in my if statement but thought it had failed because I got an error about target.something is void, however when I went back to try again I realized the error was coming from the next statement along after the first one worked (retrieving an index number from userdata) which just needed the same treatment :slight_smile:

Thanks again guys, you’ve been a big help to me :slight_smile:

I am finding the book quite helpful, but the project parts where you are supposed to “use what you have learnt” often take a bit more than the learning sections actually taught, so I get stuck like this.

I have the same problem! What is the exact solution?

For me it was what Normen suggested - using “spatial”.getParent().getName() where I would have previously just had “geometry”.getName().

Reason being that the items returned by LoadModel are generally a node, with a geometry under them. The reference to the object returns the node, the picking algorithm returns the underlying geometry, so when trying to match the found thing to our reference we need to get the picker-returned geometries parent node.

Ok but lets say I have a model in my scene which is part of an object form the class “Entitiy” which also holds parameters like “isDestroyable” “lifes” etc.
How can I get access to these parameters with a ray and then:

results.getCollision(0).getGeometry()…

?

I think there are a lot of ways you could do that, though I’m still a novice with this. I get the impression that the standard way is to assign those variables as userData of a node object (ie Entity is a Node or subclass thereof) and use something like the following to access them:

Geometry target = results.getCollision(0).getGeometry();
Node targetNode = target.getParent();

targetNode.getUserData(“isDestroyable”);
targetNode.getUserData(“lives”);

Or you might have those values tracked by a control object attached to the node, so you would use something like:

Control targetData = targetNode.getParent().getControl(“dataControl.class”);

targetData.getLives();

Using a custom class to represent an object would require a bit more thought and set-up on your part though perhaps you could store the identity of the custom object as user data on the node and then call that first?.

Ok when I create a spatial “s” and add some UserData and try to access that Data like you described it prints out “null”. If I print out the target.getParent(); it prints out the name mesh of that model. If the parent is the mesh then target should hold it right? But its null there to. Do you know whre my UserData is?

My take: Spatial is an abstract class that has both Nodes and Geometries as children. When we import a model we get a spatial which could be either of the above. More often than not it will be both - a Node with one or more geometries attached as children.

I may have gotten the exact details of the methods a little off - but I would have thought the approach was right.

My bit of working code that I produced after this original thread by the way:

[java]CollisionResults results = new CollisionResults();
rootNode.collideWith(ray, results);
Geometry target = null;
if (results.size() > 0)
{
target = results.getClosestCollision().getGeometry();
if (target.getParent().getName().substring(0, 5).equals(“Tower”))
{
selected = target.getParent().getUserData(“index”);
}
else
{
selected = -1;
}
}[/java]

Wow thanks for providing that :slight_smile:
Ok I found the solution.
This provides access to my UserData:

targetNode.getParent().getParent().getParent().getUserData(“lifes”);

Thanks for the help :slight_smile: