It looks like you're new here. If you want to get involved, click one of these buttons!
void traverseScene(orxOBJECT *child) {
orxOBJECT *sibling;
while ((child = orxObject_GetOwnedChild(child))) {
orxLOG("%s: child name", orxObject_GetName(child));
sibling = child;
while ((sibling = orxObject_GetOwnedSibling(sibling))) {
orxLOG("%s: sibling name", orxObject_GetName(sibling));
traverseScene(sibling);
}
}
}
Comments
- This will only traverse the objects that are children of the Scene node, you might have objects that are disconnected from that hierarchy.
However orx does bookkeeping on all the orxSTRUCTURE derivative that are created, if you want to iterate through all the orxOBJECTS, you can do so like this:
- Objects that have been created as part of the Scene hierarchy can decide to exclude themselves from that hierarchy at any point (usually done for permanent objects, UI objects, etc...)
- You might want to look at Scroll, which is a thin C++ layer on top of orx.
Scroll brings a few interesting features such as an in-game level editor + load/save capacity, firect binding of C++ classes to config section, etc.
Faistoiplaisir started a forum thread a while ago on this topic.
There are also other threads related to Scroll.
Acksys wrote a couple of first tutorials about Scroll.
You can look at a couple of game jam entries I wrote in the past, all using orx+Scroll, the code might be slightly outdated but the logic should still be valid:
- Mushroom Stew
- Breaktris
I always use Scroll myself for my own projects.
Just keep doing strcmp() on names until there is a match, or is there a better way?
In my pure C experiment I used a different strategy.
In Init function I traverse object structure and build user data structure based on the name of the Config section. I push config section based on the object name. I have custom keys that start with G (stands for game). So, I have GType for type of the object and other properties. Based on the custom options I construct user structure. Once user structure is built it describes game object properties, so code at runtime does not have to make string comparisons.
From code above you can see that I use orxString_Compare to compare strings and then I set user data in the end.
So, in my case "tank" name is a game type. I don't have unique tanks. Just tank type and team it belongs to. So, I don't really care for the object name except for the way of getting to configuration section.
So, during object update I can do the following:
I kind of really enjoyed this kind of model.
Now I need to see how it can be done with C++ Scroll model.
Objects all have a unique GUID, but in this case that won't help you much. All you know of your object being the name, you'd have to do a string compare.
A better approach would be to attach your data when your object is created, by listening to the orxOBJECT_EVENT_CREATE event.
The best approach, finally, would be to use Scroll which does all that (and more) behind the scene.
Well, kulak, you will have a very similar feature with Scroll, except it will be done behind the scene.
In Scroll you bind C++ classes to config section. That binding is bi-directional.
If you create an instance of a C++ class that was has such a binding, the matching orxOBJECT will be created as well and its UserData will contain a pointer to your C++ class.
Reciprocally, if you create an orxOBJECT that was bound to a C++ class, the C++ object will get created as well, and the same UserData link will be made.
Upon destruction, everything will get cleaned nicely, as it should.
Lastly, Scroll supports inheritance in its bindings.
Let's say you have a C++ class named MyObject, which inherits from ScrollObject, and you bind it to the config section Thing. If you have:
Table and Chair are automatically bound to the C++ class MyObject as well. You can, of course, override that binding if need be. Bindings are defined when Scroll gets initialized and shouldn't be modified later on.
Last thing: using Scroll means you can't access UserData for storing your own structure anymore, but as you now have a base class (ScrollObject) and as many variants as you want (all the classes you define that derive from it).
Now let's say that you don't want to hardcode all the bindings in your code, you can have a similar approach to your GType: iterate through all the config sections, when a section has the GType key, gets its value, depending on its content you can issue a binding of this section to whichever C++ class you want.
Lemme know if you have any questions.
About Scroll, I have certainly looked at it, but I'm approaching matters one thing at a time. First pure orx, then depending on what works and what doesn't...
Why don't you have the whole object scene hierarchy coming from config though?
Do you store the name somewhere in the tile config or is it hardcoded?
I'm asking all those questions as I feel there's probably a way to bypass the string compare by keeping a collection of GUIDs instead.
In config:
In code:
Parent: always refer to the scene graph, ie. physical relationship in the world defined by the tree of orxFRAMES.
Owner: same meaning as allocation ownership: if an owner gets deleted, all his children will get deleted as well.
Often an object will have the same other object as both parent and owner, but it's not mandatory as the concepts are completely unrelated.
Let's take an example: let's say you can throw sticky explosive, but if you die, they should disappear as well. When one of those stickies hits an enemy, the enemy will become its parent, whereas the player still remains its owner.
Storing a GUID makes it less efficient for retrieval, but if the matching structure doesn't exist anymore or isn't the one that you originally referenced, orxStructure_Get(GUID) will return orxNULL.
You can also increase the reference counter of the structure when storing its pointer to make sure it doesn't get deleted, however you'll have then to make sure not to forget to decrease it when you're done (otherwise that object will never get deleted). You might also disrupt the workflow when the rightful owner tries to delete that structure as you'll then become the implicit owner.
I've looked through the ini docs, but I don't seem to be able to find a description of the syntax used here:
The current description for a timeline track is:
Some questions:
- >< must be begin-command, end-command, # is the separator, but what is ^ ?
- Is there a list of available commands (such as Object.GetID, Config.SetValue) and the parameters they take?
Your questions should find answer there.
However, a quick recap (it's also in the original timeline & command forum post):
- > means push the result of the command on the internal stack
- < means retrieve the last pushed value from the stack and use it as a command argument
- ^ is a special keyword that only works for commands executed from a timeline: it'll get dynamically replaced by the GUID of the object on which the timeline/command is executed.
Commands can be used from timelines as well as from the interactive console (default toggle key: ` [backquote]).
The console is becoming quite powerful, allowing to easily change some aspects of the game, creating/modifying objects on the fly, finding texture in memory and saving them on disk, etc...)
All the available commands (and aliases) can be listed from within the console using... a command!
Ah, and of course commands can be added at runtime by the users for their own needs.
As always, I recommend people who want to follow new features and/or discuss them before implementation to subscribe to that group.
This one is depth-first, has indentations and prints the root node.
Since 2 days ago, if you wish to strictly traverse the scene graph, you can use orxObject_GetChild()/orxObject_GetSibling() instead of the Owned version, for the differences mentioned in the sticky grenade example.
Why
_uiDepth += 2;
and not
_uiDepth += 1;
What does depth + length do?
_uiDepth+strlen(orxObject_GetName(_root))
_uiDepth+strlen(orxObject_GetName(_root)) sets the printf padding
As you've already seen, in the hierarchy we can reference orxCAMERAs as well but also orxSPAWNERs.
You can check which kind of structure it is with orxStructure_GetID(), and the orxOBJECT() caster will filter anything that is not an orxOBJECT.
If you are sure of your hierarchy (set via ChildList and calls to SetParent(), not SetOwner()) and it still doesn't work as it should, it might be a bug.