Hi!
I just created an object from the class “Entity” I made myself which holds an 3D Model, Physics and so on.
With help from the tutorial on the jMonkey website I managed to implement the “shooting”.
A simple ray that follows my cam direction. Here is the code for what happens if it collides with something:
[java]
} else if (binding.equals(“Fire”) && !isPressed) {
// 1. Reset results list.
CollisionResults results = new CollisionResults();
// 2. Aim the ray from cam loc to cam direction.
Ray ray = new Ray(cam.getLocation(), cam.getDirection());
// 3. Collect intersections between Ray and Shootables in results list.
shootables.collideWith(ray, results);
// 4. Print results.
System.out.println(results.size());
if (results.size() >= 1) {
System.out.println(results.getCollision(0).getGeometry().getName());
//Material material = results.getCollision(0).getGeometry().getMaterial(); //material.setColor(“Color”, ColorRGBA.randomColor());
}
}
[/java]
So that works just fine! But only with Geometrys like a cube or something… This line:
[java]
System.out.println(results.getCollision(0).getGeometry().getName());
[/java]
displays the name of that “Geometry” i just shot. But the problem now is, that my object is not a Geometry! And I dont know how I can implement that I get the name of this object anyway. The best way for me would be if the results.getCollision(0) would return my object so I could just say “object.getName();”
Does anyone know how I can do that? I would be very grateful for any ideas
Cheers
either make your Entity class implement the Savable interface, and store it as UserData on the geometry. Or attach a control to your geometry, which has a reference to it’s Entity object inside.
Remember that the second approach means that every frame you’ll have one more call to the control, even if its only purpose is to store datas.
@wezrule : and this is also true with the appstate. I think that it might be a problem. Sometimes, i have things like the asset manager (or close to that : something that is only here to do some initialization and/or provide some service) and i don’t need at all the update part. Hey, it’s not a big deal to have ONE update every tick for no reason at all, but when the number of such items grow, it could become a bit annoying. I think that in future versions it could be a good idea to tag an appstate/control as “doesn’t need update” or (different approach) have a new interface that is only here for this “service providing” stuff.
This is on my “suggestion for jme 4” list, with a lot of other things, but i don’t really know where i can talk about it.
If theres nothing done then it will be completely inlined by the JIT, I doubt you will see any performance hit through this. Amd as wezrule said, for simple data (or even complete classes if you extend Savable) you can use UserData.
it’s still in the update loop. I don’t know how appstates/controls are stored, but no matter if it’s with an array or a linked list, the jit is not smart enough to “skip” this iteration step. Well, it’s only an iteration, not something big, i know. But if you want to add a lot of properties to your nodes (like for an entity system) you’ll end up with a lot of controls idling but still updated every frame. And if you store then in the userdata, you have an access that use a string comparison, which is slow.
Add a field that is internally a map (enum->object) and we are good : no update, fast access, no problem with mispelling the key. Hey, you can even oblige the enum to implement an interface like that:
[java]
public interface Typed
{
public Class getValueType();
}
[/java]
and add an assert in the insert method of the map that check that the value is correct. It’s just removed when compiling for release and show you the moment where the wrong data is added (not when it’s used) so you’ll know exactly where you need to fix it.
And you can have the same thing for the “appstate” : a map of non-updated fast-accessed and (partially)type-checked properties.
It’s not as good as type check while compiling, but it’s better than nothing. And all the “debug” stuff is automatically removed for release.
Asserts are only for debugging and are disabled in deployed applications. UserData is pretty much what you describe. Comparing existing strings is optimized to the bone, its not slow at all. Basically its a hash map based on the strings hash. Finally all of this is completely dwarfed by the render call.
AppStates do not belong in this discussion of performance at all, anyway. It’s an array iteration and they can already be disabled to skip their updates. The overhead of a single method call is immeasurably small in modern java. Fractions of a nano-second or something. (For reference, the one synchronized() that is in AppState manager and is done every frame will dwarf the isEnabled() calls of many dozens of app states.)
Controls have some extra overhead only because they tend to be numerous. If the control array is empty then the iteration is bypassed but there is no allocation and little overhead in an array iteration. And if you already have one control on your spatial then there is little reason to avoid adding another.
You’d have to have thousands and thousands of spatials before any of this was measurable compared to the other stuff going on… and then your scene has other issues and is already rendering slow, anyway. And that’s measure in millisecond time, not nanosecond.
Wow, I learned a lot reading this
First off: Thanks for the answers!
So if I understand you guys right the best solution atm would be to extend Entity of Savable and put it as a UserData onto a Geometry. So I can type .getGeometry().getUserData(“entity”);
This returns my object “entity” from “Entity” and I can access it?