I might be misunderstanding what you said, but wouldn't using if-statements be less bloated?
You just have a variable in the units that indicates which team they belong to
and you have a boolean variable that indicates whether they are ground units
and you have a boolean variable that indicates whether they are infantry units.
You can then loop over every gound infantry unit of the opponent by:
Code:
with obj_unit_parent {
if team != other.team
&& am_ground
&& am_infantry {
...
}
}
The thing is, you need to have a lot of different inheritances especially if there are different rules for all different unit types. For example, a ground unit type will have a Create event with things that are different from an air unit type for variables and such, and an infantry unity and a vehicle unit type will also need different considerations, however, one needs to seamlessly combine ground + infantry, ground + vehicle, air + infantry, air + vehicle. Now multiply that with a lot of unit types. And not just Create events, but a whole host of events concerning movement, selection, AI handling specific unit types for battle composition, and such.
Having terrain (and general) collisions would also be factored. For example, air units will always be never collided upon, so adding if statements to collision events is more bloated than not having collision events at all.
With collisions also comes wholly different movement. And many units would share movement "engines", some wheeled, some tracked, etc. Yes, you can set each unit with its own engine by having separate code for each, but if you need to share them, and you can't use inheritance (because inheritance is used by detection unit types first, not terrain unit types) except through event_perform or instance_change.
So when all such considerations are in place, not just detection, to loop per object type makes more sense than setting booleans by that point. And where instance_change can come in. (Though right now my system uses event_perform a lot instead of instance_change)
Of course some would suggest to simplify the system, however, I'm aiming for an RTS system that replicates modern RTSes in flexibility.
As noted by my signature, I have been making RTSes as my specialty for a long time, and using if statements to regularly check for unit types seems more efficient for just detection, until you realize you need units that are more robust and flexible at the same time with a host of other things. There's a reason this genre is one that is not often tackled by game developers, and its because it needs to be a balanced system made up of bloated resource directory (that's the tradeoff), not a haphazard one with bloated code of if statements.
What GMWolf proposed is a way to implement a state pattern in GameMaker.
The state pattern is used for instances that change their internal state and have their behavior change as a result of it.
You don't have units that change their internal state (which categories they belong to), but rather have a static state that is only used to put labels on units.
This isn't quite what GMWolf's suggestion is meant for.
So your premise is false, because it isn't a static state, or rather, at its simplest form, it is a static state, but when complexity is added, it is now internal states I'm dealing with.
Simple static state: only relies on detection
Complex internal state: relies on detection, terrain, movement, AI, etc.
If you would use instance_change, I suppose you would either:
- Have duplicate objects with different parents, which would be a bad idea in all ways I can think of.
Already have a working system of objects with multiple inheritances and multiple parents, again, using event_perform. No biggie, I'm used to thinking with multiple inheritances already. You just need to have distinct, non-conflicting roles for each.
- Have the objects temporarily change to the parent object currently being checked for, but then:
* you need to keep track of the original object index in every unit
Not really necessary, you just need instance id. Then use data structures to take out non-qualified ones per cycle.
* you need to implement the logic of which object may be transformed to which categories (which will inevitably be less nice than just stating these facts as boolean variables in the create event of the units).
Already accounted for.
* you will either need to keep track of which instances have been selected so far and keep looping over those instances only when checking for the next category, or you'll have to work per instance, in which case you'll be using those if-satements anyway, but with just more intermediate and less clear steps inbetween.
When you're already dealing with complex RTS detection (range, 3D z isometric coordinates, terrain, fog of war, stealth, cloaking, etc. considerations), splitting it up per object type is my preference.
So instead of dealing with which side the unit is on, I'd be dealing only with stealth and fog of war in said code. It's arguably much cleaner.
- Have for each unit an object defining its behavior and a bunch of dedicated objects representing a category for that unit specifically (which would have their respective category objects as parent), so that you can change to those objects when checking for said category and then change back. This would have almost the exact same issues as the previous approach.
- Have an object to represent an instance is selected. You would again have similar issues.
Many solutions.
For example: put all close units in a list with detection unit type, cycle through each unit, instance change all units to their terrain unit type, cycle through again, change them back.
OR
Have global events where each instance_change is on one step, and then on another step, switching back and forth based on the current mode.
Again, I understand I'm only transferring the bloat from if statements to a bloated resource tree, as stated. That is preferable.