Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><em>If</em> your bullet owners are frequently changed (e.g. deallocated), the pointer-to-pointer approach is suitable. The union solution does not address this concern directly; as presented, it does not support deallocating ships without touching the pointer on each of that ship's bullets. Of course, that may actually be a practical solution in some implementations, e.g. if you have a need to find all the bullets of a given player, you could maintain a linked list of them: a “next_bullet” pointer for each bullet and “last_bullet” pointer to the head of the list for each player.</p> <p>And instead of allocating each bullet separately, I would also follow mjv's suggestion of pre-allocating some number of them and picking the next available one. In the linked list implementation, you could use the same “next_bullet” pointers to maintain one list of pre-allocated bullets not currently in use. The advantage of this approach is that you could easily allocate more if you ran out of them, instead of maintaining an array, i.e. if the list of available bullets is empty just add them to the list on demand. Similarly, put “expired” (exploded?) bullets back into the list of available ones and the amount allocated will automatically adapt to however many is required.</p> <p>Another thing that comes to mind is that you might not need to know which particular UFO (or other enemy) owns a given bullet; just have a single pointer (e.g. <code>SHIP **</code>) for the owning player and set it to NULL for all non-player bullets. If this is not suitable, you could also consider storing the type of each owner in the beginning of owner struct itself, e.g.:</p> <pre><code>enum EntityType { TYPE_PLAYER_SHIP, TYPE_UFO_SHIP, TYPE_BULLET, }; struct GameEntity { enum EntityType type; // This struct is not actually used, it just defines the beginning }; struct Ship { enum EntityType type; // Set to TYPE_PLAYER_SHIP when allocating! … }; struct UFO { enum EntityType type; // Set to TYPE_UFO_SHIP when allocating! … }; struct Bullet { enum EntityType type; // Set to TYPE_BULLET when allocating! struct GameEntity *owner; … }; struct Bullet *ship_fire (struct Ship *ship) { Bullet *b = get_next_available_bullet(); b-&gt;owner = (struct GameEntity *) ship; return b; } void hit_asteroid (struct Asteroid *ast, struct Bullet *bullet) { if (bullet-&gt;owner &amp;&amp; bullet-&gt;owner-&gt;type == TYPE_PLAYER_SHIP) { … } } </code></pre> <p>Note that this trick relies on pointers to different types of structs being interchangeable, and the single enum being stored at the same offset in each type of struct. In practice these are not unreasonable assumptions, but I'm not certain that this behaviour is strictly guaranteed in standard C (however, e.g. <code>struct sockaddr</code> uses the same trick, and it's used by various POSIX networking functions like <code>bind</code>).</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload