#"Best Practice" for items present on a map and UI list

1 messages · Page 1 of 1 (latest)

final scroll
#

Hey, this is less of a "How do I specifically" and more of a "What's the best way to do this" kind of thing.

The situation:

I have a split-screen UI as the entire viewport of the game. Half the screen is a 2D map. Right now literally just a ColorRect with a starfield type material on it. Ships, asteroids, planets, and other objects in the solar system depicted in the 2D map will each reside there, and will move around (not looking forward to the orbital mechanics, that'll probably come much later). The other half of the screen is a few containers that ultimately contain a Tree node that should be a list of all objects on the map.

The third component of this is an Autoload I've made that keeps a dictionary of all objects in the star system (on the map), with some basic details on them, including name, type, and an object identifier that's just an integer. Right now I call that my ObjectRegistry. I have an InWorldObject class that contains a lot more details, including the OID, and my goal is for each object on the map to correspond with an instance of InWorldObject or something that extends it.

Right now, when I instantiate a new InWorldObject, I do so from the tree, which exists in the main scene. The tree simultaneously instantiates an InWorldObject and accesses the ObjectRegistry to use the same instantiation arguments to register the new ship.

My question:

What's the best practice for keeping these three different expressions of the same object in sync? My current idea is to have either the tree item or the object on the map be the actual InWorldObject, with the other stuff just referring back to it. But I'm worried that if I ever want to have objects not on the map, that would require a major refactor. It would also mean I'd have to autoload the Map and the Tree as well as the registry, which may or may not be a problem.

#

Furthermore, at some point I'm going to want to "crunch" these items down and abstract the whole map, aggregating all of the objects as more abstract concepts like total resources and manufacturing capability. I don't know that that's going to matter to the solution, but I wanted to point out that the contents of the tree and the map will change and start over during gameplay, and I will eventually need to transfer at least some of the ships present during the "crunch" into the next map.

high crow
#

IME think about UI frameworks like Model View Controller.

#

ignoring how you're implementing them, think about the roles each of these representations fill and what they're for, etc

final scroll
#

The issues with the solutions I've come up with so far...

Having the Tree entry be the InWorldObject means that I'm going to have to find a way to translate its coordinates to the map and use that for an icon on the map. It sounds like that might be a clunky way of doing things, I feel like there's a better way.

Having the item on the map means that if I ever want to take the item off the map for any reason, I'll have to find some way of preserving it.

final scroll
high crow
#

it's a general software concept, so it might not be perfect for you; you might also be doing something down the rabbit hole like MVVM etc. But the idea is that you should be able to diagram out the relationships between your entities and the data flows between them

#

and particularly if you find that more than one of them is being mutated, Look Out! Because that means that you've got a very complex model, and are strongly encouraged to simplify!

final scroll
#

Yeah, I'm diving down that right now. So far it looks like my thinking has been poking at (my poorly understood version of) that concept.

high crow
#

(also, you could think about how physics handles a very similar problem, where e.g. RigidBody2D has a global_position, but there's a shadowy mirror of it in the physics server (the DirectState objects), which it has to maintain regularly in sync with each other)

final scroll
#

Haven't messed much with physics, either, but I'm gonna have to get my hands real dirty with it whenever I'm ready to implement orbital mechanics, so I might as well get a head start now.

high crow
#

the answer is that complexity sucks, and so if you can simplify the ownerships and roles (for instance: the ObjectRegistry is actually an object summary and it's not necessarily accurate data, just summarized, and that irregularly...), that will help you figure out what they're for and what their update cycles need to look like

final scroll
#

Yeah, right now the ObjectRegistry is intended to be just that. All of the specific data and methods are kept in the InWorldObject. The items in the Registry are literally just Name, Type, Coordinates, and OID.

#

Good to hear that I got that concept right, at least.

high crow
#

rectify your names, maybe -- Registry doesn't imply Summaries, so you may find yourself (or your team -- you're going to make a billion dollars and hire a team, right?) abusing it some dreary 2am coding session

final scroll
#

Right.

#

I'm not under any illusions of this being big or making a ton of money, lol. I'm just making the kind of game I'd like to play, by myself.

high crow
#

no no no. A billion dollars, with a "tr". Good luck!

final scroll
#

Thanks!

#

Hrm. I understand scope pretty well as a coding concept, but I am still a little fuzzy on how the scopes of nodes and scenes work. In this case it seems like I would want the individual objects on the map to be child nodes of the map itself, but I don't want to make a child node in the Godot editor because that would necessarily make an instance of that node on the map, right? Am I following best practice by having the in_world_object itself be its own scene, or should I be reconsidering my hierarchy?

high crow
#

In this case it seems like I would want the individual objects on the map to be child nodes of the map itself, but I don't want to make a child node in the Godot editor because that would necessarily make an instance of that node on the map, right?
Yes, if you put a node into a scene, it is because you want to use that node in that scene.

I think I don't understand the question [yet].

final scroll
#

Fair nuff. I think the answer here will be for me to use signals.

#

I am still bumbling around access issues and am not quite used to Godot's ways of handling scope and access.

high crow
#

access: it's pretty open. The closest it comes to variable hiding is the convention to start a name with _, and the ui hiding child scenes' child nodes by default (they're there! They're just not displayed unless you turn that on)

final scroll
#

Well, I have nodes that are parallel, not child nodes. So InWorldObject is its own scene, it's not a child of Main.

high crow
#

scope: I think you are bringing a foreign concept in, and pointing at something real with a word which is an imperfect match for the concepts actually being used here, I am afraid. There are many different technologies which Godot uses to establish scoping, not really one unified "this is what a scope is in godot"

final scroll
#

As I have it right now, without signals, InWorldObject can't access anything in Main, and vice versa... as far as I understand it.

high crow
#

You have a SceneTree, and it has children. All nodes (that are actively being used...) are somewhere in this tree. There's nothing very magical about parallel children (cousins/uncles/neblings in the tree)

#

though if you don't use get_node("../Something"), you obviously don't need to fear accessing each other by mistake 😄 That's what I mean talking about the information hiding being "by convention" vs something more rigorous

final scroll
#

I might have different SceneTrees, then. InWorldObject doesn't appear anywhere in my Main scene. I think I need to brush up on scenes and scene definition. Been over a year since I did the tutorial on them and I'm only now getting back into Godot.

high crow
#

you do not. Godot has one scene tree, it is a real class

final scroll
#

Gotcha.

#

I'll read up on that, I'm sure this is rooted in a fundamental misunderstanding on my part.

high crow
#

(though actually, I'm only being so harsh because, ofc, we talk about the scene.tscn file defining a Scene Tree all the time, and I was not using it in that sense)

#

But anyway, at any given time you have a root window, and everything you're using is a descendant of it over time

final scroll
#

I appreciate your help! I'll probably update this from time to time as I need. I wouldn't say you're being harsh at all, you're being quite patient, lol.

high crow
#

when godot talks about a "current scene", it's really just a convenience for you

#

the truth is there's a SceneTree with a root node it owns (the godot game, configured with your project settings)

#

and everything else you do modifies its children, including a helpful current_scene pointer on the scene tree object, pointing at a child of this root node

#

so: if two scenes are not loaded & made children of the root simultaneously then they can't refer to each others' nodes since those nodes in a real sense don't exist

final scroll
#

So when I go to File -> New Scene or make a new .tscn file in my project directory, I am not making a new Scene Tree, but instead just adding a Scene to the existing tree?

high crow
#

no, you're making a new scene file (which we sometimes talk about as having a scene tree of nodes; really, SceneTree was probably a bad name 😄 )

#

but anyway, that scene file can be instantiated and its root node added to the (singleton) scene tree

#

(and it could be added as the current_scene, or added as a child to some other node already in the tree)

#

and there is no power on earth that can stop its nodes from then crawling around the tree and taking references to each other with get_node and get_parent and get_children and so on

#

and it's a bad idea to do that!

#

but you can 😄

final scroll
#

Gooot it. Okay. Rather than taking references, we'd want to use signals, right?

high crow
#

you have a lot of options. Depends what you're doing and what the relationships are.