Alright, here are the things that come to mind when skimming through your sources. Please note that this is not a complete (or even formally correct) code review, so they're just suggestions/ideas you can consider or throw away.
// particle animation types #define EXPLOSION AL_ID('A','E','X','P') // the particles are forced outward #define IMPLOSION AL_ID('A','I','M','P') // the particles are drawn inward ... int anim_type; // Either EXPLOSION or IMPLOSION int prim_type; // either LINE, SPRITE, or CIRCLE
This looks like a perfect application for an enum. Generally, try to avoid preprocessor #defines where you can.
Also, use consistent nomenclature. I've seen anim_type and maxDistance. Unless you have a very good reason to distinct those two by using different styles, I suggest you choose one and stick to that.
int CreateParticleAnimation(int maxp, int col1, int col2, BITMAP *t, Sprite *s, float f, int d, int at, int pt, int x, int y, float mSize, float mDis);
This has too many parameters for me. Rule of thumb is to limit parameters to 7, the less, the better. There might be need for more complex structures/patterns to circumvent this, so it's probably easier to just keep it as-is.
This one's mostly stylistic: I always prefer the order public, protected, private to foster the idea of an interface. Unfortunately, C++ doesn't allow truely hidden members. There's the Cheshire cat pattern (also known as PImpl), but that's still not "it". Think about what might be of interest to someone just using the class (not extending it). Those things are best put at the top, there's no need to look at private members.
Hmmm ... why CreateParticleAnimation and DestroyParticleAnimation? Sounds like a constructor/destructor pair. Maybe you don't need those methods at all.
bool InUse() { return used; } void IsUsed() { used = true; } void UnUsed() { used = false; }
By reading the names of these methods, I would never guess the actual outcome. Try to use better names, especially InUse() and IsUsed() are confusing. On a similar note, you can make InUse() a const method, like so: bool InUse() const { ... }. Rule of thumb is to make as much const as possible.
if(texture) destroy_bitmap(texture);
Two things: One, after you destroy_bitmap the texture, set it to 0. Two, and this is a very pedantic style issue, compare texture to 0. Everything not a boolean should be compared to a value. Someone reading if(texture) might deduce that texture in fact is a valid pointer inside its block, but that would be misleading (mind dangling pointers).
The whole type-dependent stuff (line, sprite, circle, and implosion/explosion) looks like a perfect application for polymorphism. You could extract the relevant behaviour to classes of their own, thus encapsulating functionality more. Something to think about .
void ParticleAnimation::SetScreenPosition(point_t *p) { position.x = p->x; position.y = p->y; }
This one's unsafe. What happens if p is 0? Also, you make a deep copy anyway, so I suggest passing p as const point_t &.
(edit: Even better would be to let point_t handle the copying, and just do position = p; in SetScreenPosition. If you don't have any pointers or sensitive data in point_t, this works out of the box. If you do, you're well advised to implement operator = yourself.)
pAnim = (ParticleAnimation*)malloc(sizeof(ParticleAnimation) * nP);
Hm. Unless you want to the plain pointer approach for educational purposes, I suggest you switch to an STL container, like std::vector or std::list. There are already enough resources dealing with those (also here in the forum), so I won't go into detail here.
Well, that's about it what came to my mind. Further comments would require better analysis of your code's structure, which I cannot afford time-wise right now. Hope you can make some sense of my drivel.
Good luck with your particle engine!
This looks like a perfect application for an enum. Generally, try to avoid preprocessor #defines where you can.
Haven't used enums in ages, but I might look into that. I don't really remember how to use them, but i've got plenty of books and info on the subject.
Hmmm ... why CreateParticleAnimation and DestroyParticleAnimation? Sounds like a constructor/destructor pair. Maybe you don't need those methods at all.
In CreateParticleAnimations, there is memory allocated, and if an error occurs the error message is returned. I generally don't like using malloc or any of those kinds of routines in constructors. But perhap I can put the DestroyParticleAnimation in a destructor.
Two things: One, after you destroy_bitmap the texture, set it to 0. Two, and this is a very pedantic style issue, compare texture to 0. Everything not a boolean should be compared to a value. Someone reading if(texture) might deduce that texture in fact is a valid pointer inside its block, but that would be misleading (mind dangling pointers).
Alright, so you mean if texture == NULL? Fair enough. Also, I've found that if i tried to destroy a null bitmap it gave a massive runtime error. A lot of my programming habits have come from my experiences with DirectX, hence my use of classes and such.
By reading the names of these methods, I would never guess the actual outcome. Try to use better names, especially InUse() and IsUsed() are confusing. On a similar note, you can make InUse() a const method, like so: bool InUse() const { ... }. Rule of thumb is to make as much const as possible.
What purpose does const serve when it comes to functions? Seriously, I don't know. Furthermore, these are for internal use by the ParticleEngine, and not intended to be called by another class or function.
Hm. Unless you want to the plain pointer approach for educational purposes, I suggest you switch to an STL container, like std::vector or std::list. There are already enough resources dealing with those (also here in the forum), so I won't go into detail here.
That was a oversight on my part. usually i only use malloc for structures, and the new keyword for classes. but i've not needed an array of classes for a while, so malloc has become second nature. Would a better approach be:
pAnim = new ParticleAnimation[nP];
By the way, did you see the thread i started about how much I hate RLE sprites? I used vectors fo those, and it gave me runtime errors all over the place. And i generally prefer not to go there as they're just too bloody hard to understand and there are no coherant tutorials i can find on the net. I prefer malloc or new.
Thanks for your comments. Just so you know, I am not intending on making this a user-friendly Particle Engine; it is purely another building block in my current programming project. And since I won't be releasing the final source code for the game, I don't see any reason to make the nomenclature neat and clean. Not to sound rude. However, these comments have been found useful in my own analysis.
What purpose does const serve when it comes to functions? Seriously, I don't know. Furthermore, these are for internal use by the ParticleEngine, and not intended to be called by another class or function.
It makes the this pointer const, meaning you'll get a compile error if you try to modify any non-mutable members. The purpose of this is that a method declared as const guarantees that it doesn't change the object's state. If those methods are intended for internal use only, you should hide them by making them private.
And since I won't be releasing the final source code for the game, I don't see any reason to make the nomenclature neat and clean. Not to sound rude.
Not sounding rude, no worries . After all, it's your project, not mine, so do whatever you see fit. However, for your own sake, I want to stress the point of consistent nomenclature for future work. As a programmer, you shouldn't have to look up whether a specific variable's name was max_size or maxSize (for example). With consistent naming, you'll never run into such situations. Let the code rest for a few days, and it will become an issue if you have to extend/modify it later on.
(edit: The bottom-line being that you shouldn't worry about "low-level" stuff like this. Better break your head over algorithms. )