Missile Tracking

Started by
37 comments, last by Jotaf 15 years, 2 months ago
ooh, sounds pretty cool. I'll have to check in wxDev-c++ to make sure the appropriate options are set, but that should be trivial. Anyway, I see now. I can effectively use it to check if one object accessed through the interface provided by its parent (yay, inheritance) is in fact an object of a type derived from said parent.

<just getting this clear in my head>
Using something similar to the code you posted below, a missile_launcher object would be accepted, but a kew_gun (my in-code name for railgun... KEW = Kinetic Energy Weapon) would not since it is a totally different class albeit derived from the same parent. In this way I can selectively issue commands to objects of a desired derived type without needing to mangle the interface. Awesome. It may still be a little weird to expose this new interface level without compromising the modularity of the system, but I think I can do it (*playertarget should only be passed when its the player's weapon... if the instance is in an enemy ship it should use whatever the pointer to that enemy's target is).

Thanks again [grin]
There was a saying we had in college: Those who walk into the engineering building are never quite the same when they walk out.
Advertisement
I would've still used the double-pointer, or its variant with the "Target" helper class, but dynamic_cast is ok [smile]

If your problem was passing too much info on update(), for example to dumb missiles, you're defeating the purpose of a general interface. Either every class is happy with the same interface, or you design special code for different cases, which dynamic_cast allows you to.

Know that in production code (for many people at least) it would be completely acceptable to pass redundant arguments in a generic function for a base class (ie, void Base::update(Ship *target)). What's the overhead of passing one more parameter to any decently sized function anyway?

That would be the overhead you'd incur for dumb missiles. It's a single pointer that they wouldn't use. It implies a lot of info (target state, position, speed, etc) so it would be useful for a lot of other classes. Everything else like the remaining ships and projectiles should be available as a sort of global state (whatever your implementation for that may be), so this list of parameters is unlikely to grow.

Sometimes the quest for extremely optimized code gets in the way [rolleyes] You replaced a simple parameter with a dynamic_cast that has to be specialized for each sub-class that needs the "target" parameter. It may hurt maintainability a little, but ok; it can be seen as a matter of preference [smile]
I have not made the change yet (and I still haven't figured out how to pass *playertarget to the player's weapons only... but I have an idea), so I am still open for suggestions. As for the cast, I plan on framing the update calls the same way for all types that require targets, and so they should be able to take the same call. The only difficult part will be passing the player's target only to those weapons which belong to it.

As for the double pointer thing, that is my preferred method... but I couldn't figure out how to apply that to the code I posted earlier with the design goals in mind. If you can see through the jumble and can figure it out, I would be happy to try it.
There was a saying we had in college: Those who walk into the engineering building are never quite the same when they walk out.
As a test, I have implemented the method using the dynamic cast and wow does it work [grin][grin]. And it just so happens that pShip.fireAll is handled separately from other ships, so I can give it *playertarget directly. This means I can still isolate the player from the other ships and maintain proper modularity. Awesome. Jotef: I'm still interested in your method if you can figure out how to get it to work and you think its better.

Thanks for all your help, folks!
There was a saying we had in college: Those who walk into the engineering building are never quite the same when they walk out.
Well your problem is solved (for now [wink] ) but anyway I think I found a better solution, better even than the auxiliary Target class [smile]

Since every ship (player or otherwise) would own a Target, why not move that data inside the ship class and let each Projectile reference the ship that fired it?

class Ship {  ...  Vector pos; //this ship's position  Ship *current_target; //this ship's current target; make it an iterator if you want!};class Guided_Missile : public Projectile {  Ship *guide; //The owner of this missile, guiding it to its target(s)  Guided_Missile(Ship *new_guide) : guide(new_guide) {};  void update() {    Vector target_pos = guide->current_target->pos;    //go to target_pos...  }};class Bullet : public Projectile {  Bullet() {};  void update() {    //simply move along current velocity  }};


So if the "guide" changes its mind (sets its "current_target" to something else), that target will be used instead by any Guided_Missiles.

You may want to watch out for when the ship that fires the missile is destroyed. Many ways to handle that; and in-game, that could mean they keep following their current target, or they're instantly destroyed, or they start spiraling off in a random direction (which would be pretty cool)...

dynamic_cast is very useful but I'd save it for another situation [wink]
At the moment, I'm handling ships in kind of a stupid way. I free up the memory but do not deconstruct them first. So pointers back to something are still valid up until that data is overwritten. Obviously this is incredibly dangerous, so that will soon change. Anyway, your method does look promising, I will give it some consideration.

Right now, I do not update my missiles' targets mid-flight. They acquire a target on launch and stick to that path so its really just the weapons I'd have to be concerned with. And if a parent ship dies, its weapons die with it and stop firing. So, missiles already fired will stick to their courses, and no new ones will be spawned (this is more CPU efficient than updating each missile since it was never in my design spec for the missiles to change targets mid-flight anyway).
There was a saying we had in college: Those who walk into the engineering building are never quite the same when they walk out.
Ah I got that impression somehow, that you wanted to change the targets mid-flight. Then what stops you from having a function like this

void Weapon::fire(Ship *target);

and different constructors for projectiles, like this

Guided_Missile(Ship *target)
Bullet()

?
I could do that, the only issue is that it would introduce a useless element to the function call for most projectile types... and also understand the call to firs does not spawn the projectiles, it triggers the weapons to update themselves and then fire. It is the weapon objects which spawn the projectiles. Still, its not a bad way to do it, its just no better than the dynamic cast method.
There was a saying we had in college: Those who walk into the engineering building are never quite the same when they walk out.
*Ahem*...
Just replace "update" with "fire" or whatever.

Quote:Original post by Jotaf
If your problem was passing too much info on update(), for example to dumb missiles, you're defeating the purpose of a general interface. Either every class is happy with the same interface, or you design special code for different cases, which dynamic_cast allows you to.

Know that in production code (for many people at least) it would be completely acceptable to pass redundant arguments in a generic function for a base class (ie, void Base::update(Ship *target)). What's the overhead of passing one more parameter to any decently sized function anyway?

That would be the overhead you'd incur for dumb missiles. It's a single pointer that they wouldn't use. It implies a lot of info (target state, position, speed, etc) so it would be useful for a lot of other classes. Everything else like the remaining ships and projectiles should be available as a sort of global state (whatever your implementation for that may be), so this list of parameters is unlikely to grow.

Sometimes the quest for extremely optimized code gets in the way [rolleyes] You replaced a simple parameter with a dynamic_cast that has to be specialized for each sub-class that needs the "target" parameter. It may hurt maintainability a little, but ok; it can be seen as a matter of preference [smile]


This topic is closed to new replies.

Advertisement