setUserData() vs. Controls: Which is best practice?

Do you have the link to your published game? I’m sure we’d all love to take a look at your finished work.

…and if not finished yet, then let me know when you get to the tigers.

The game itself is not finished, but all the code as far as the units are concerned is done. The AI works great, attack animations and explosions are all done, building and moving units all done.

I’m not going to apologize if I don’t buy into the whole my way is the only way philosophy. I did it, it’s done, it works, it was easy.

Most likely what we have here is what’s often referred to as a fear of inadequacy. It’s quite common and, apparently, especially common among programmers and in some cases may more appropriately be labeled impostor syndrome.

Basically you secretly believe that you’re not that great of a programmer and afraid that others will discover what a terrible programmer you are. As a means to protect this secret you attack others usually on the very issues you, yourself, are afraid of in an attempt to belittle their work thereby making your work appear better by contrast.

Again this is quite common and I see it all the time. No hard feelings friend. I’m sure your work is wonderful and you need not belittle the work of others to make it appear so.

Hilarious.

Nah, your arguments are so funny because I made almost the exact same ones myself 15 years ago or more. I’m only trying to save you time but you are welcome to continue doing things the hard way if you enjoy it.

“We choose to go to the Moon! … We choose to go to the Moon in this decade and do the other things, not because they are easy, but because they are hard; because that goal will serve to organize and measure the best of our energies and skills, because that challenge is one that we are willing to accept, one we are unwilling to postpone, and one we intend to win …” -JFK

Which would be a valid analogy only if there were some folks off to the side asking the president why he isn’t using the elevator that’s already there.

NASA Engineers: “Mr. President, how about you just take the elevator to the moon that we already built?”
President: “Nah, I’m going to do things my own way… besides, it’s probably a long elevator trip so I’d have to bring snacks and stuff. I’ll just create a spaceship instead…”

1 Like

It wasn’t meant as an argument, but as a comical means to frame a response. As for the elevator, you even said yourself that it’s not that great of a solution.

Really the way I’m doing it, which is already done and working, was precicely the way the Java developers intended this functionality to work. This technique has been used, successfully, time and time again by a great deal of applications that have different objects that make use of a common set of variables and methods.

If I were developing a system intended to be used by a wide audience for a variety of different purposes I might consider a different approach, but I’m not. The system developed for Carpe Diem is only intended to be used with Carpe Diem.

Generic code works great for mass production indeed, but custom built generally outperforms generics because it’s better suited to its specific case use.

Again what I’m doing is precisely the reason the abstract keyword exists, I imagine the Java developers threw it in for a reason.

If it is a mistake to use this method then using it will serve to teach me why it is a mistake and that knowledge is worth far more than simply avoiding it without understanding why.

Nonetheless it is implemented, it does work and it is quite easy to work with.

You see, for instance, I have units that do different things when a particular method is called. So instead of having to determine what the unit is and then call the appropriate method, I can just call the same method on every unit and the units class just overrides that method of the superclass. Easy peasy

Moreover storing and accessing variables with a string key gets messy, typos are all too easy so you may just end up creating variables to store the keys to help avoid typos and then you’re doubling the number of variables used.

Plus you have to consider if you have different entities with different variables then you probably need a variable to store the unit type so you know what variables to access, using subclasses means you can just use typeof to determine the type of unit.

Yes, I more or less said as much. That’s fine. But you will understand that when providing advice to someone who is just starting out and may not have the talent to make the harder approaches work, the community will steer them in a more appropriate direction.

If we see someone who has never painted a complete floor before we might suggest options to keep them from painting themselves into a corner later.

Yes. It’s called polymorphism and it can be well covered through composition as well as inheritance. The only major difference between the two approaches of specialization or composition is that the former requires a rigid class hierarchy and the latter injects its functionality.

public class MyGameObject {
    public static final String KEY = "myGameObject";

    ...the stuff....  
}

someNode.setUserData(MyGameObject.KEY, new MyGameObject());

…and if it actually does stuff instead of hold data, use a control instead.

No one in their right mind recommends storing half a dozen separate fields as user data. One field, maybe two.

Well, if we want to go full on into an entity component system, nothing needs to know ‘types’ because types are arbitrary and generally only useful to humans and not computers. An “Entity component system” is the full on power of total composition as every feature exists mostly on its own and they cut across all objects that happen to hold that particular piece of data.

But even way short of that, avoiding specialization (ie: subclassing) in favor of composition reaps benefits over the long run wherever you can use it.

1 Like

I understand that absolutely, however; when I am in search of a solution to a particular situation I prefer to have access to as many different options as possible so I am better able choose that which bests suits my particular situation.

And again each technique has situations in which it works well. JavaFX, for instance, uses a rigid hierarchy of subclasses for all of its controls. Custom JavaFX controls generally have their own dedicated classes.

Really you’re just attaching an object to another object, attaching your game object to the Node object, why not just extend Node and add your game object code there and get rid of the extra class altogether?

Sure you might have to do some casting if you’re using more than one type of game object, but even still you’ll have to do that casting anyway every time you access that game object from UserData.

Well you’re going to have to know the type of an object if you’re going to be accessing a variable or method that is specific to that object type. You can’t call getMaterial() on a Spatial, you need to cast it to a Geometry, but you also need to know that it is a Geometry object and not a Node object because Node doesn’t have a getMaterial() method. Although my extended Node class does, it just exposes the getMaterial() method on the Geometry attached to it. I can do that because I know that it will have a Geometry attached to it, but in general jME code you can’t assume that a Node will have anything attached to it a all.

So if you have different entities with different variables, some of which are common, then you can create an abstract class that holds the common variables and subclasses that hold the unique variables and only do a cast when you need access to the unique variables. Otherwise you can do a class that holds all the common and unique variables allocating unnecessary space on the heap for each entity.

I understand this might not be an issue for those with plenty of memory, but not everyone in the world has 8GB+ of memory. There’s also readability to account for.

1 Like

What about when you want to make a network game? You’ll end up pulling all of your visualization specific classes over to the server. What if you want to combine the behaviors of two subclasses? Well, you’re out of luck there.

Composition supports all of those things… in addition if you decided to use some different game engine tomorrow then your game code transfers directly.

Visualizations classes are not game objects… even if you choose to mix them. So casting to Geometry, getting materials, etc… not really relevant to a discussion about game objects or entity systems.

An entity component system doesn’t work like that. The code that uses objects gets views of that object with only the stuff it is interested in. The rendering system asks for all objects with position and model info, for example. It’s only job is to render objects. A sound system might ask for all objects with position and sound type… and so on.

So if some entity has a position component, a model info component, and a sound component then it gets rendered and has sound. The code that renders didn’t need to know anything about the code that has sound… and neither of them cared whether the entity was a Tank or a Horse or a CaptainFirstClass.

At that point, only the player cares about the “types” of things and then it’s just a name.

But really this is not the proper place to do an entity component system justice. If you are truly curious then you can look up the literature and try to read it with an open mind. (I was originally dead set against them until I absorbed the t-systems articles and implemented on of my own… I got to delete about 30-40% of Mythruna’s code at the time.)

Anyway, even without that, there is no material difference between Unit extends Node and Node.setUserData(Unit) or Node.addControl(Unit). Both accomplish basically the same things. The former ties you forever to client side JME and allows you to do some potentially dirty intermingling of state, the latter doesn’t.

1 Like

Whoa, what a debate. :smiley:
Anyhow @Tryder, nobody is judging you if you are doing things differently. I understand what @pspeed is trying to say. He is trying to teach everybody some good code design, which is great. There is nothing wrong with inheritance, it’s just that when your project will grow and you will have to do some refactoring, you will find it harder and will spend more time doing that. If from the very beginning you try to use some good code design practices and patterns, you program will be much more adaptive to change.
All of this is actually nicely written in the Effective Java book, which I consider one of the best books on Java ever.

But back on topic: I also suggest saving just the ID of your game object into the user data of a spatial and have actual game logic separated from the visualization part.

Well that’s precisely my point, that each method has its use cases and I don’t plan on using a headless server so what I have works well for what I’m using it for. There’s nothing wrong with your suggestion, it has its uses too, but for my needs I think I’ll stick with what I have.

My project is just a turn based strategy and I’m not going to be renting space on any servers or buying my own so there’s no need for a headless server, I’ll be writing my own networking code that just runs in a background thread. There won’t be any information communicated between the client and server that requires class casting on either end.

One of the beauties of turn based, things like networking are much simpler than real-time stuff. Everything’s very clear cut.

P.S. Not that it really matters at this point anyway, I’ve got until Friday to find another place to live and there really doesn’t seem to be any prospects on the horizon.

Actually I just met situation where using UserData looks like the only applicable method I can think of to keep logical part in sync with visual. In short: I have traveling burst that can possibly hit any visual object during his lifetime. Using ray casting and knowing burst dimensions I can get what model was really been hit, and where exactly, and I can complete visual part, no problems here. Now I have to traverse back to logic somehow (to update shields level, hull level etc etc) - and this means I have to get entity ID which is not so straightforward, as model factory can create exactly same models for actually different entities. The only way to get exact entity ID is to store it (during creation of model) in UserData, isn’t it?

1 Like

Yep, and that’s generally the only thing I personally use UserData for… my entity ID.

On the other hand if you already have a Control to invoke animations, remove the object from the scenegraph or things like that on the spatials nothing is stopping you from adding a getId() method as well…

The pattern I have applied to my space game is the following:

Spatial data is used for two types of data sets:

 1) Default values per spatial that controls will use: example The rotation control for a planet used the default rotation speed on each planet spatial
 2) Spatial specific runtime data: example ... health of a ship

Controls contain all if the data elements that they need for their runtime state and are serializable in order to save the state of the entire game when I bring the system down for maintenance in order to be able to bring up the system without loosing state.

Appstates contain the data that is needed to orchestrate spatials within a scene. Also serializable for the same reasons as controls.

my system wich creates the spatials keeps a map spatial to uuid updated.

On hit i can then traverse the sceengraph parentwise untill i find one in the map.
Might be slower, but not noticeable, and i only need to keep track of one map.