Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: General "World" object data structure?  (Read 2864 times)

0 Members and 1 Guest are viewing this topic.

Moogooloo

  • Newbie
  • *
  • Posts: 4
    • View Profile
General "World" object data structure?
« on: December 17, 2013, 03:11:02 am »
     Hello! I'm a student at UCSC studying game design, and a group of students and I recently used SFML in a Game AI class. We ran into some problems that led to some not-so-well-thought-out quick-fixes that caused us a lot more problems. Now that the project deadline is past, I'd like to ask some more experienced programmers what the optimal solution is.

     We followed the SFML Game Design book (and the corresponding source code) in order to set up our game object and other classes. When we got to input, we had a lot of problems understanding the C++ code used with the Command class and how it was implemented.

     For those of you who haven't read it, the Command object is used to pass functions to your game objects. For example, change gameObject1's velocity by a certain amount. To execute these functions, each command is also assigned a category, and the code that executes the commands will only do so on game objects that match that command's category.

     This is fine for the game that was developed in the book, where you might have 3 enemy categories, who are all moving in the same pattern. However, we wanted to demonstrate steering behaviors in our game with an arbitrary number of enemies (up to a max, probably). We originally planned that we would have an EnemyController class that would create the commands and push them onto the command queue. However, our first main problem was that each one of our enemies needs different changes in velocity, so the category system wouldn't work for us, unless we somehow gave assigned an enemy a unique category. My slap-dash fix to this was editing the command object to, instead of a category, take a SceneNode& as an argument. This sort-of-kind-of allowed us to pass commands to different SceneNodes, but created some circular dependencies and other problems: Anything that needed to create commands would need access to the SceneGraph to get the right node, so pretty much everything had a pointer to our World object, and the code was, frankly, really bad.

     How would you have done it? If a World object has access to all the SceneNodes in the SceneGraph, how can I handle telling SceneNode's how to move for an arbitrary number of SceneNodes where the category system won't work?

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11032
    • View Profile
    • development blog
    • Email
Re: General "World" object data structure?
« Reply #1 on: December 17, 2013, 09:42:25 am »
The SceneGraph that got developed in the book was oriented around making more or less fix joints between multiple entities. It sounds like you guys are doing something different, thus such a fixed approach is not very wise. So I guess you need to think of a different way to approach the scene graph.
While the command system of the book is quite nice, it can also be a bit limiting. You could think about implementing a message bus instead. That way you can just send messages and only the one interested in the message and react to it. Tank wrote a nice article about it. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: General "World" object data structure?
« Reply #2 on: December 17, 2013, 11:32:00 am »
However, our first main problem was that each one of our enemies needs different changes in velocity, so the category system wouldn't work for us, unless we somehow gave assigned an enemy a unique category.
But the actions didn't really differ logically, there was only a different value for the velocity? Wouldn't it be possible to use one category, but in the command, you differentiate cases depending on the enemy (ideally not explicitly, but through some kind of map or a property in each enemy)?

My slap-dash fix to this was editing the command object to, instead of a category, take a SceneNode& as an argument.
I don't think that's meaningful, SceneNode& is the type on which the command executed -- you don't know it beforehand. However, you can use another type than the Category::Type enum to identify entities. If you don't need to combine different flags, just use int. Otherwise, something like std::bitset might be a possibility, or a dynamic list of receivers.

But as eXpl0it3r mentioned, don't try to force the design of our book to any application. As emphasized in the book, there are always trade-offs. It doesn't mean you have to throw away everything; for example, scene graph and command system are orthogonal concepts and can be used independently. It's also possible to have additional data structures to reference entities directly, or to create groups/hierarchies which are not related to rendering (e.g. for collision or flocking behavior).

There are also a lot of threads about game design on this forum, don't hesitate to search. For example, there was recently a discussion about integrating more sophisticated collision detection and response into the design of the SFML book.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Moogooloo

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: General "World" object data structure?
« Reply #3 on: December 18, 2013, 02:03:11 am »
The SceneGraph that got developed in the book was oriented around making more or less fix joints between multiple entities. It sounds like you guys are doing something different, thus such a fixed approach is not very wise. So I guess you need to think of a different way to approach the scene graph.

I have only ever worked with SceneGraphs as they were implemented in to book. Besides the "tree" implementation, what are other ways they can be done? Do you know of any literature that discusses this type of thing? I've searched all over for 2D game development books, but all of the ones I've found don't really discuss what I'm looking for.

While the command system of the book is quite nice, it can also be a bit limiting. You could think about implementing a message bus instead. That way you can just send messages and only the one interested in the message and react to it. Tank wrote a nice article about it. ;)

I've never heard of this design pattern, thanks for sharing! In the context of the SFML book, does this mean that every entity needs its own ID? If this is the case, then I feel like I run into the same problems that I would trying to get the category system to work with my project. Does every entity created get the next available ID? After an entity is destroyed, does the next new entity get the newly-freed ID?

However, our first main problem was that each one of our enemies needs different changes in velocity, so the category system wouldn't work for us, unless we somehow gave assigned an enemy a unique category.
But the actions didn't really differ logically, there was only a different value for the velocity? Wouldn't it be possible to use one category, but in the command, you differentiate cases depending on the enemy (ideally not explicitly, but through some kind of map or a property in each enemy)?

As it was implemented in the book, we need to pass the arguments to our command's function at the time we create the command, right? Like so:

Command moveLeft;
moveLeft.category = Category::PlayerAircraft;
moveLeft.action = derivedAction<Aircraft>(AircraftMover(-playerSpeed, 0.f));


Obviously, steering behaviors are dependent on current position, surrounding entities and obstacles, and whatnot. Ideally, I would have loved to use commands like so:

Command wander;
wander.category = Category::Wandering;
wander.action = derivedAction<Enemy>(Wander());


... and then have the wander function take care of everything. But like I said, the command wouldn't have access to the data it needs to.

My slap-dash fix to this was editing the command object to, instead of a category, take a SceneNode& as an argument.
I don't think that's meaningful, SceneNode& is the type on which the command executed -- you don't know it beforehand. However, you can use another type than the Category::Type enum to identify entities. If you don't need to combine different flags, just use int. Otherwise, something like std::bitset might be a possibility, or a dynamic list of receivers.

My thought process was that, if the command had access to the reference to the SceneNode it was executing the action on, then I would be able to use commands like I wanted to above. Clearly, this defeats the purpose of the command system in a way, and I don't like what we did at all. If I extracted the wander function somehow and then set the command action like so:

sf::Vector2f newVel = wander(SceneNode&);
wanderCommand.action = derivedAction<Enemy>(EnemyMover(newVel));


then I would need a category for each enemy, and the categories would have to update and change as new enemies were spawned, similar to the ID questions I asked above. I didn't know how to deal with that, and it didn't sound optimal, but perhaps in retrospect, that would have been better than needing every command to know the SceneNode it is executing on beforehand.

But as eXpl0it3r mentioned, don't try to force the design of our book to any application. As emphasized in the book, there are always trade-offs. It doesn't mean you have to throw away everything; for example, scene graph and command system are orthogonal concepts and can be used independently. It's also possible to have additional data structures to reference entities directly, or to create groups/hierarchies which are not related to rendering (e.g. for collision or flocking behavior).

There are also a lot of threads about game design on this forum, don't hesitate to search. For example, there was recently a discussion about integrating more sophisticated collision detection and response into the design of the SFML book.

Thanks for the link, I'll definitely be frequenting these forums now. I know that I shouldn't be forcing any design onto something it isn't optimal for. However, at this point I feel like I'm lacking for literature discussing these things, so I don't know the concepts that would help me design my own classes. I learn well through example, normally through tinkering with working code, and I figured that would be enough to help me in this project but it didn't :P. In my head, I imagine some CurGameState struct that would have all the data about everything on the screen, which would get updated per tic and all of my controller classes can access it to do their functions, but I don't know how I would go about doing that. These are the things that make me wish I had more books.  :(

Thanks both of you for taking the time to answer me.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: General "World" object data structure?
« Reply #4 on: December 18, 2013, 10:16:07 am »
Besides the "tree" implementation, what are other ways [scene graphs] can be done?
Scene graphs are trees that provide a rendering hierarchy, but there is of course a variety of other data structures to organize your units. For spatial optimization, Quadtree might be worth a look at. The purposes are however different.

Obviously, steering behaviors are dependent on current position, surrounding entities and obstacles, and whatnot.
Before even thinking about whether and how commands can be used, can you tell us a bit about your design? How does a unit/entity/agent in your system look?

Why does an entity have to compute its steering vectors? As you have seen, this requires knowledge about the surrounding world -- both when you use commands and when you don't. Isn't it more appropriate to calculate steering vectors in a central place, and pass them to the entities so that they can apply them?
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Moogooloo

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: General "World" object data structure?
« Reply #5 on: December 18, 2013, 09:52:53 pm »
Obviously, steering behaviors are dependent on current position, surrounding entities and obstacles, and whatnot.
Before even thinking about whether and how commands can be used, can you tell us a bit about your design? How does a unit/entity/agent in your system look?

Why does an entity have to compute its steering vectors? As you have seen, this requires knowledge about the surrounding world -- both when you use commands and when you don't. Isn't it more appropriate to calculate steering vectors in a central place, and pass them to the entities so that they can apply them?

My "game object" class is the same as it is implemented in the book. SceneNode inherits sf::Transformable, sf::Drawable, and sf::NonCopyable. Entity inherits SceneNode, and my game objects like Spacecraft and Enemy inherit Entity.

I'm having trouble visualizing "a central place". Are you suggesting that I could have my World class calculate these vectors? Or a seperate class?

Thanks for mentioning QuadTree, I'll look into it.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: General "World" object data structure?
« Reply #6 on: December 18, 2013, 10:37:18 pm »
Yes, World for example. Or a separate class dedicated to steering.

Your situation is very similar to the one in the collision thread I linked above -- please read it, maybe it clears up a few things.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

 

anything