Sign in to follow this  

Help me design my movement system properly

This topic is 3857 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

My current game has two kinds of locations that can be occupied by units: Provinces, and ProvinceBorders. (So you can be in Kansas, Oz, or the Kansas-Oz border.) Now, when a unit is ordered from one place to another, it needs to know what its next step is. (Going from Kansas to Oz, your first step is the border.) It seems to me that the unit should not be keeping track of what kind of location it's in. Rather it should simply see a Location::nextStep(Location* goal) method, for my provinces and borders to overload. So, is there an elegant way I can do this without casting? My first solution is to put three virtual methods in the Location class:
  virtual Location* nextStop (Location* goal) = 0;
  virtual Location* nextStop (Province* goal) = 0;
  virtual Location* nextStop (ProvinceBorder* goal) = 0;
which takes care of the immediate problem. But clearly this isn't very extensible if I need to add another subclass of Location. Better solutions?

Share this post


Link to post
Share on other sites
Why do you need different methods for provinces and borders? This isn't clear to me. I'd just model the map as a graph, with provinces and borders as vertices and border-province connections as edges and then run the whole thing through a shortest-path algorithm like the Floyd-Warshall algorithm.. Then you'd just need the "Location* nextStep(Location*)" method to spit out the precalculated solution.

Share this post


Link to post
Share on other sites
Alternately you can make some base class BaseLocation, that Location, Province, and ProvinceBorder all inherit from, and then pass that as the argument. Then you only need one method signature:

virtual Location* nextStop (BaseLocation* goal) = 0;

Share this post


Link to post
Share on other sites
So what you have is a map of nodes, where nodes of type A only connect to nodes of type B, which in turn connect to exactly two nodes of type A?

Is there a significant advantage to having "NodeA and NodeB" over just having "Node.type = A and Node.type = B"?

What, exactly is the functional difference? Is there a difference in logic, or a difference in methods? What is common between them?

Share this post


Link to post
Share on other sites
Quote:
Original post by erissian
So what you have is a map of nodes, where nodes of type A only connect to nodes of type B, which in turn connect to exactly two nodes of type A?

Is there a significant advantage to having "NodeA and NodeB" over just having "Node.type = A and Node.type = B"?

What, exactly is the functional difference? Is there a difference in logic, or a difference in methods? What is common between them?


That is precisely the kind of graph I have, yes. The distinction is imposed by the logic of my economic system; there is no particular advantage for the movement part, in fact it causes problems! But I'm really quite happy with the way my economic system works, so the movement system for units will just have to accommodate that.

Quote:
Alternately you can make some base class BaseLocation, that Location, Province, and ProvinceBorder all inherit from, and then pass that as the argument. Then you only need one method signature:

virtual Location* nextStop (BaseLocation* goal) = 0;


I don't understand how this is different from the solution I already have, except that it introduces an additional and un-necessary layer of abstraction. To be clear, Province and ProvinceBorder both inherit from Location.

Share this post


Link to post
Share on other sites
Province store production units; ProvinceBorders store the difficulty of getting from one Province to another, the number of transport units assigned to that route, the infrastructure built, and a couple of other things.

Share this post


Link to post
Share on other sites
Not in the same way. Which, indeed, is why I need my two Location subclasses to handle things differently. :)

Edit: I guess what you're saying is that, since there is a genuine difference in the interface, the military units do in fact need to know about the difference, so I should expose the Province and ProvinceBorder classes directly?

Share this post


Link to post
Share on other sites
The way I would do it, just because of the way I plan things, is to have one node type, which has flags indicating any special properties, and whose information is exposed to all units. That way, if I decide that some information may be related to two different kinds of units, I don't have to have copies of variables, or adjust the superclass beyond its scope. Also, if I chose to make a third unit type which required the information from both sets, it would add unnecessary complexity to the problem.

In other words, when I design things, I don't just think of "How am I going to use this?" but I try also to think of "How am I going the change this later?"

Ultimately, you have to do what makes sense to you, but I would just make it a single, very informative class, which you can exploit however you need to.

Share this post


Link to post
Share on other sites
Just because you need the 'virtual' keyword for some functionality doesn't mean you need to apply it to everything. If the find-next-location algorithm is the same for Provinces as it is for ProvinceBorders (and it should be; you can presumably represent pointers-to-neighbours internally as base Location pointers), then just put that functionality in the base class (and just accept a base Location reference for the destination).

Also, consider using references for the input parameter and return value rather than pointers (although a pointer might be useful for the return value so that a NULL indicates "sorry, can't get there from here"). In general, you prefer references at the interface level, and pointers within the implementation (i.e., as data members of a structure).

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
Just because you need the 'virtual' keyword for some functionality doesn't mean you need to apply it to everything. If the find-next-location algorithm is the same for Provinces as it is for ProvinceBorders (and it should be; you can presumably represent pointers-to-neighbours internally as base Location pointers), then just put that functionality in the base class (and just accept a base Location reference for the destination).


I think you've put your finger on it. The find-next-location is not the same for Provinces and ProvinceBorders, because they have different restrictions on how economic units can move. However, those restrictions are not actually relevant to how military units move. Therefore, I should only expose that particular path-finding to the economic system, and write a different one for the military system, instead of trying to shoehorn everything into the economic pathfinding. Fortunately I wrote my A* to be quite general, it doesn't know anything about Provinces and ProvinceBorders. :)

Share this post


Link to post
Share on other sites

This topic is 3857 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this