A better way
SonShadowCat

At the moment, the way I am casting spells is very bulky and odd. There is a casting function for each spell and if this goes on there will be quite a number of functions just for casting spells. Now I dont see a way that I could incorporate it all into 1 function and I was wondering if anyone could help me out here.

here is some code so you can see the primitive way im doing things( remember, the firing controls are just temporary until I add more spells):

1 if( key[KEY_LCONTROL]) // If left control is pressed
2 Cast_Metal_Arrow();
3 
4this is in the input function
5 
6 
7void cPlayer::Cast_Metal_Arrow() // Cast the metal arrow spell if player has enough materials
8{
9 if( (Materials[Wwood].size() - cMetal_Arrow::Wood) > 0) // If the player has enough wood
10 {
11 if( (Materials[Iiron].size() - cMetal_Arrow::Iron) > 0) // If the player has enough iron
12 {
13 if( Shot_Delay > cMetal_Arrow::Shot_Delay)
14 {
15 Spells[Metal_Arrow].push_back( new cMetal_Arrow( X_Pos, Y_Pos, Direction));
16 
17 Materials[Wwood].resize( (Materials[Wwood].size() - cMetal_Arrow::Wood));
18 Materials[Iiron].resize( (Materials[Iiron].size() - cMetal_Arrow::Iron));
19 
20 Shot_Delay = 0;
21 }
22 }
23 }
24}
25 
26this is the casting function.

I for one cannot think of a way to shrink all the casting functions such as this into 1 function which will know what to create and such. Any help would be appreciated

Korval
Quote:

I for one cannot think of a way to shrink all the casting functions such as this into 1 function which will know what to create and such. Any help would be appreciated

Polymorphism. This is a classic polymorphism problem.

Clearly, you need to have a spell base class, and have each spell derived from it. Each individual spell has a "cast" function, that is virtual. Then, when the player needs to cast a spell, you pass in some ID that tells the player which spell you're talking about, it looks that ID up in it's spell list, gets the spell object, and calls "cast".

james_lohr

Yeah you definitely want a sort of base spell function/class. To have to write a whole new function every time you add a new spell is not good.

If a spell needs to do something really unique then by all means write something separate for that spell, but call it from the base spell function with a pointer to the function or something.

For the spells in my RPG, I had a text file with all the separate spell parameters so it was possible to create a new spell without doing any coding at all (provided the spell didn't do something completely unique). An even better idea would be to make a spell editor but this would only really be needed if you were making a lot of spells.

The above only applies if you're going to have a fair few spells. If you planning to have like 4 then you may as well do it all in the code.

Tobias Dammers

Yes, try to break it down to parameters and a handful of truly different things a spell might do. Parameters might be the attack radius, an animation, damage done to the target, you name it. Then make a basic spell class, plus a derived one for each different type of spell, with a number of parameters.

SonShadowCat

I am already doing polymorphism and I guess I didnt explain myself well.

I cannot have a cast spell inside a class if there is no object of the class to call the function. In the code, you see that im creating a new instance of the class and subtracting all the needed spell materials. There is no way in my mind that I can have a function that takes the currently selected spell, somehow makes a new spell in the vector, and subtracts the materials since I know of no way to do this:

Spells[Metal_Arrow].push_back( new cMetal_Arrow( X_Pos, Y_Pos, Direction));

with different spells in 1 function without have t o resort to a switch or many if's to determine the current spell and create the appropriate spell.

james_lohr

I probably shouldn't try to help with this seeing as I know very little about classes but here's what I think I would do:

-I would make a spell class which would primarily be a data structure with a load of spell related functions.

-I would then create an instance of this class for each spell type (a simple array of classes). This would use a separate constructor to the one described below. This constructor would require only one parameter: the spell type (eg which text file to load the spell parameters from)

-Then when actually attempting to cast the spell, I would extract the parameters such as mana cost, required level etc from the already created array of instances. If the requirements are met and the spell is cast successfully then a new instance of the class is created by copying one of the already loaded instances. A few more parameters may need to be passed to the copy constructor such as the initial spell position, direction etc.

Of course I've never actually written my own class for anything, I'm just going on two lectures I had on classes in Java. Sorry if I'm talking BS.

It would be so much easier if you were just using C!! None of this class instance nonsense ::).

ImLeftFooted
Quote:

None of this class instance nonsense

Personaly ive found classes very useful, and a hell of a lot easier to understand. But thats just me

if your trying to avoid if statements, i might even create a recuirments class, that would be included in each spell class. There might be a better way, but ill show you what I mean:

1//this will do all your if statements for you, making things easier.
2class REC{
3private:
4 int energy;
5 int mandrake;
6 int wand;
7 //etc...
8public:
9 REC() {energy=mandrake=wand=/*...*/0;}
10
11 void setEnergy(int e) {if(e>=0)energy=e;}
12 void setMandrake(int m) {if(m>=0)mandrake=m;}
13 //etc...
14 
15 bool calcualteCase(PLAYER &p){
16 if(p.getEnergy()-energy >= 0)p.setEnergy(p.getEnergy()-energy);
17 else return false;
18 
19 //etc...
20 
21 return true;
22 }
23};
24 
25//this would also make it easy to upload spells from a file, by having a dynamic array of spells and reading all the recs from a file
26 
27//ex spell class
28class SPELL{
29private:
30 RECS recs;
31 int coolDownTime;
32 int timeSinceLastCast;
33 int x, y;
34 bool beingCast;
35 BITMAP *animation[];
36 int animationFramCount;
37 //you probably need some more here for like direction and things like that
38public:
39 SPELL(string); //will upload RECS from file, along with coolDownTime
40 SPELL() {coolDownTime=timeSinceLastCast=x=y=beingCast=/*...*/0;}
41 
42 bool Cast(PLAYER &p) {if(recs.calculateCast(p)) beingCast=1;}
43 
44 void poll(BITMAP *des); //will draw animation
45};

Well, something like that. Its missing collision detection with enemies and some other stuff, but hopefully this helps.

And this might look clumsy here, but in practice it can make things easier.

Korval
Quote:

I cannot have a cast spell inside a class if there is no object of the class to call the function. In the code, you see that im creating a new instance of the class and subtracting all the needed spell materials. There is no way in my mind that I can have a function that takes the currently selected spell, somehow makes a new spell in the vector, and subtracts the materials since I know of no way to do this:

This makes no sense.

At some point, you determine which spell to cast, whether the user selects it from a list or chooses certain spell material components or whatever. Once this is done, you just get the instance of the spell and cast it. You should have an instance of all possible spells in some list. No need to constantly be allocating and deleting them. If an invokation of a spell needs to stick around (it has some lingering effects on the world), then the spell class should allocate some object to provide that functionality. The spell class itself should not represent this change in the world.

Quote:

I would make a spell class which would primarily be a data structure with a load of spell related functions.

That presumes that spells only differ from oneanother between some data parameters. What happens if you want spells to do something more interesting? Like altering game rules, or various other things? You'd have to have each spell have these data structures and so forth. And, whenever you expand the list of things it that any spell can do, you have to expand this data structure for all spells.

It's more flexible to have separate classes for spells. Even if they just define the category of spells (attack, defense, etc), that goes a long way into making a more flexible system.

SonShadowCat
Quote:

No need to constantly be allocating and deleting them

Yes I do because the spells are like bullets, they stay for a while, they dont just happen and the go away.

james_lohr
Quote:

That presumes that spells only differ from oneanother between some data parameters. What happens if you want spells to do something more interesting?

I said:

If a spell needs to do something really unique then by all means write something separate for that spell, but call it from the base spell function with a pointer to the function or something

But yeah I agree, I separate class for each spell category would be best.

nonnus29

I'll throw my two cents in here...

A spell in a game like ssc is talking about emplies alot of behavior. What you want to do is add an object to the world that will :

1. move thru the world
2. have effects on other objects in the world
-cause damage to other objects/enemies/whatever
-change attributes of other objects
3. will have a limited lifespan
4. it will have a varying area of effect
5. etc...

This emplies two things: creating the spell object (which ssc is dealing with now) and implementing the spell objects ability to tell other objects when it hits them what it does to them.

Casting spells sounds like a great case for a factory (usually a singleton but it doesn't have to be). Your spell factory could have a function like:

CSpellObject CSpellFactory::createSpell(int SPELL_TYPE, CMobileGameObjectThatCanCastSpells &player)  {

// in here you would have a big*ss switch like
// in your first example and go thru each spell 
// type and check if the player has the stuff to 
// cast it etc... 
//
// or call a function in your script to create the 
// spell
}

Then add the spell object to the world Vector or however you are managing your objects.

Obviously the actual spell object is going to have some well defined behavior. In your bullet example its going to fly along until it hits something. Now we're talking about collision detection and response. This emplies messaging between objects. This is what gui's do. One thing some gui designs do is pass 'Event' objects back forth between one another.

This is a pretty fundamental behavior so it would seem be a good function to include in your base class:

1CObject {
2 public:
3 void init();
4 void update();
5 void render();
6 CEvent collide(CBoundingBox box);
7 private:
8 Vector &every_object_in_the_game;
9}
10 
11CEvent CObject::collide(CBoundingBox) {
12 // iterate thru the Vector and check for
13 // collision. (EDIT 2: probably want to do this
14 // iteration in the update method? not sure.)
15 // Call that objects collide method
16 // and process the CEvent object it returns.
17}

I haven't actually done that, but I've seen it done...

EDIT; just wanted to add this is NOT trivial stuff; in fact its stuff like this (complex behaviors, messaging between objects etc...) that stopped my rpg project dead in its track 8 months ago. The teaser is if you can figure out how to do it 'easily' and extensibly (ie scripting) you can add all kinds of wacky behaviors to your game.

Korval
Quote:

Yes I do because the spells are like bullets, they stay for a while, they dont just happen and the go away.

You didn't seem to fully understand what I said.

Consider the casting of the spell to be everything that happens inside of the "CastSpell" function. If the spell has an instantaneous effect, like knocking off hitpoints, then it should do so. However, most spells will, at the very least, have some unique visual effect, like a bolt of lightning. These spells will, therefore, need to create a sprite that draws a bolt of lightning in the appropriate place. For a bullet-like spell, the spell class's "CastSpell" function will spawn a "SpellBolt", which is a first-class entity with AI. The AI of the object will guide the bolt to the target.

A Spell class itself shouldn't be a sprite or a first-class entity. It should just be the code that does the effects. Effects that last after the moment of invokation should be handled by objects created by the Spell class.

Quote:

If a spell needs to do something really unique then by all means write something separate for that spell, but call it from the base spell function with a pointer to the function or something

Anytime you start tossing function pointers around in C++, you should instead be using classes, unless you have to because you're interfacing with a library that uses them.

SonShadowCat

Im really not understanding you korval, im sorry. The first code box nonus has is exactly what Im trying to avoid.

Okay, there is no cast function in the spells classes themselves, to do so would be incredibly stupid since I would not be able to call it. What im trying to do is this: I press cast key, a function gets called that looks at the current equipped spell, and creates space in the appropriate spot of a vector( a multi-dimensional one, I think thats what they-re called). There can be many many instances of the same spell which is why reserving 1 spot and using it over and over( as I think you said) wont work here.

Im probally just going for the big switch route since I cant explain myself quite well.

Nonus: I already have all collision detection down. And this isnt an RPG, just an action game with spells and some attributes.

Krzysztof Kluczek
Quote:

Okay, there is no cast function in the spells classes themselves, to do so would be incredibly stupid since I would not be able to call it.

Wouldn`t public+static methods do? :)

SonShadowCat

But they wouldnt be useful in this situation now would they o.O

Krzysztof Kluczek

If you are going to end up with a big switch they could help only in moving code outside the player class to spell class, which is IMHO more logical.

Another approach is to create an array with one spell object of each spell. They shouldn`t be accessible from map and shouldn`t have they logic run (collision, movement, etc.). Now you could use public virtual+static (is it possible?) method and use spell id to select proper spell object from that array and run that method with caster parameter.

SonShadowCat

Im not that good at C++ so this part:

Quote:

Now you could use public virtual+static (is it possible?) method and use spell id to select proper spell object from that array and run that method with caster parameter.

didnt make much sense to me...im not sure how that would help me, could you explain?

Krzysztof Kluczek

I checked, virtual+static is not possible, but static isn`t needed here.

1class CSpellBase {
2public:
3 int CheckResources(CPlayer &caster,int metal,int wood)
4 {
5 if(caster.metal<metal) return 0;
6 if(caster.wood <wood ) return 0;
7 caster.metal-=metal;
8 caster.wood -=wood ;
9 return 1;
10 }
11 
12 // parameters can also include target, etc.
13 virtual void CastMe(CPlayer &caster) = 0;
14}
15 
16class CMetalArrow {
17 public:
18 virtual void CastMe(CPlayer &caster)
19 {
20 if(!CheckResources(caster,10,10)) return;
21 // create spell projectile
22 // which may be the same class
23 // (CMetalArrow)
24 }
25}
26 
27 
28// somewhere else
29// these objects aren`t on map
30CSpellBase *spells[MAX_SPELL_ID];
31 
32 
33// and casting function
34void CPlayer::CastSpell(int id)
35{
36 if(spells[id])
37 spells[id]->CastMe(*this);
38}

I hope I can speak C++ better than english. ;)

SonShadowCat

Your code still doesnt help me with my original problem :P. And your english isnt what is confusing me, its my lousy ill-worded question.

edit: I dont see how this works:

class CMetalArrow {
  public:
    virtual void CastMe(CPlayer &caster)
    {
      if(!CheckResources(caster,10,10)) return;
      // create spell projectile
      // which may be the same class
      // (CMetalArrow)
    }
}

How does it create a new projectile? and how would I call the function to begin with since your code doesnt show you allocating memory for the array of pointers.

Krzysztof Kluczek

Ok, here`s the missing part:

void CAMainGameObject::InitSpells()
{
  array[SPELL_METAL_ARROW] = new CMetalArrow();
  array[SPELL_SOMETHING_ELSE] = new CSomethingElse();
  // etc.
}

And code placed in CastMe() function should create object of class CMetalArrow, put it inside game logic, set up velocity, color, target, etc. Some of these steps of course can be done by calling a method from CSpellBase shared between all spells.

Of course you can put the array into one of the objects (my C habits showed up).

Anyway, I think it won`t help much since the array initializing code isn`t better than switch. If you decide to use switch, I suggest using CastMe methods the same way, but they should be rather static than virtual.

1class CMetalArrow {
2 public:
3 static void CastMe(CPlayer &caster)
4 {
5 // definition is the same:
6 // - check/decrease resources
7 // - create object of class CMetalArrow
8 // - put it into use
9 }
10};
11 
12//...
13void CPlayer::CastSpell(int id)
14{
15 switch(id)
16 {
17 case SPELL_METAL_ARROW: CMetalArrow::CastMe(*this); break;
18 // etc.
19 }
20}

SonShadowCat

I still dont see how CMetalArrow::CastMe(...) creates an object of itself if its in the class.

Krzysztof Kluczek
class CMetalArrow {
  public:
    static void CastMe(CPlayer &caster)
    {
       CMetalArrow *missile = new CMetalArrow();
       missile->SetPosition(caster.position);
       missile->SetDirection(caster.heading);
       World::objects.put(missile);
    }
};

Korval

I'll make it really simple for you.

1class Spell;
2 
3class SpellCaster
4{
5protected:
6 //This just holds a list of instances of Spell*.
7 //These are allocated when the class derived from
8 //this one is allocated. These are destroyed when
9 //that class is destroyed.
10 vector<Spell *> m_SpellList;
11public:
12 bool CastSpell(SpellName theSpell)
13 {
14//Performance note: replace this with faster search
15//code if you have lots of spells.
16 int iSpellIx;
17 for(iSpellIx = 0; iSpellIx < m_SpellList.size(); iSpellIx++)
18 {
19 if(m_SpellList[iSpellIx]->GetName() == theSpell)
20 break;
21 }
22 
23 if(iSpellIx == m_SpellList.size())
24 return false;
25 
26 m_SpellList[iSpellIx]->InvokeSpell();
27 return true;
28 }
29};
30 
31class Spell
32{
33public:
34 SpellName GetName();
35 
36 virtual void InvokeSpell() = 0;
37};
38 
39class SpellBolt
40{
41protected
42 class EnergyBolt : public Entity
43 {
44 //Do whatever you need to to create an entity
45 //that tracks a target.
46 //Note that all Entity classes add themselves to
47 //the main entity list. They kill themselves when needed.
48 //There is no need to keep a pointer of these around.
49 }
50 
51public:
52 virtual void InvokeSpell()
53 {
54 EnergyBolt *pTheBolt = new EnergyBolt();
55 
56//Set the target to track
57 pTheBolt->SetTarget();
58 
59//Set starting location
60 pTheBolt->SetStartLoc();
61 
62//Done.
63 }
64};
65 
66class BoltSpell
67{
68protected:
69 
70public:
71 virtual void InvokeSpell();
72 {
73 Entity *pTarget = GetTarget();
74 
75 pTarget->DoDamage(iDamageValue);
76 
77 //SimpleSprites, like Entity's, control their
78 //own lifetimes. A SimpleSprite plays a single
79 //sprite animation, then kills itself.
80 new SimpleSprite(/*Lighting bolt animation to play*/, /*Where to play it*/);
81 }
82};

As you see, the character has a list of spell objects. When asked for a spell, it just searches the list; no big switch/case statement. All you need is to have something to initialize that list from.

A Spell creates persisitant objects, or directly does damage, or both, as necessary. The spell does not persist; only the effects it creates do.

SonShadowCat
m_SpellList[iSpellIx]->InvokeSpell();

Doesnt this imply you can only have 1 instance of any type of spell? Thats what it looks like to since ive never ever seen code like what you've done, especially this:

EnergyBolt *pTheBolt = new EnergyBolt();

Perhaps its because I havent eaten much in weeks or maybe I am just too stupid, but I really cannot grasp this.

class SpellBolt
{
protected
  class EnergyBolt : public Entity

What is entity? And why is the Spell class all alone, shouldnt the other spell classes inherit from Spell?

And doesnt this also imply you can only have 1 instance of the spell:

  virtual void InvokeSpell()
  {
    EnergyBolt *pTheBolt = new EnergyBolt();

I wonder why its so hard for me to grasp this.

Krzysztof Kluczek
EnergyBolt *pTheBolt = new EnergyBolt();

Since pTheBolt is a pointer to a newly allocated object, you can store it wherever you like and have many EnergyBolt objects at time. :)

SonShadowCat

So I could create a vector for say EnergyBolt and do this:

push_back( *pTheBolt);

right?

I could do this for every spell, but would it be the best way?

Korval
Quote:

So I could create a vector for say EnergyBolt and do this:

push_back( *pTheBolt);

right?

As I pointed out in my comments, classes derived from Entity store themselves in a list and take care of their own lifetimes. An EnergyBolt derives from the same class as a Player or a Creature or whatever else is out there. So you don't have to be concerned about having a vector of EnergyBolts.

Of course, that's how I would organize my Entity classes. You don't have to do that. But, if you don't, then you have to deal with managing objects allocated by spells. I would suggest using self-managing objects as much as possible.

nonnus29

One thing about Korvals example that may be confusing to ssc is Korval is separating the spell effect from the spell; so he is talking about two different things; the spell and the energy bolt the spell creates. So you only ever need one instance of a spell and this one spell instance can create multiple energy bolts.

Something that is confusing to me is the use of inner classes, maybe someone could explain that? I knew you can do it in java but I've never seen it done in c++ before. Why wouldn't energy bolt be a separate class?

gillius

There's not much technical reason to do inner classes in C++. It's a matter of phycological design. For example in Java Swing you can use an anonymous class, a nested private class, or a public class. Most people use the first or second method as external objects don't care about the mouse listener object that works only for one type of object.

SonShadowCat

Shouldnt SpellBolt and BoltSpell derive from spell since they all have the InvokeSpell function? And How else would you get the name of the spell then?

This part is confusing me to hell and back:

  class EnergyBolt : public Entity
  {
   //Do whatever you need to to create an entity
   //that tracks a target.
   //Note that all Entity classes add themselves to
   //the main entity list. They kill themselves when needed.
   //There is no need to keep a pointer of these around.
  }

public:
  virtual void InvokeSpell()
  {
    EnergyBolt *pTheBolt = new EnergyBolt();

Isnt this implying that SpellBolt can only make 1 instance of EnergyBolt? In InvokeSpell, im going to have create a switch arent I? So I can check which type of spell to invoke?

new EnergyBolt();

Why are there ()? Its a class so why does it look like a function.

vector<Spell *> m_SpellList;

Now, for this vector, At the beginning of the program, I add all the different types of spell categories( as I assume SpellBolt is a category and not an actual spell)?

I just dont get the SpellBolt class and EnergyBolt class. If SpellBolt is an actual spell,
then why do we need EnergyBolt?

And is BoltSpell cast when the spell hits the target?

Im sorry im bothering you so much, I dont understand why its troubling me so much.

Krzysztof Kluczek
Quote:

Why are there ()? Its a class so why does it look like a function.

Because it`s a constructor call, with no parameters in this case. Constructor is a class method that is named exactly like the class, eg.:
EnergyBolt::EnergyBolt();
If a class have no constructors written, no parameters constructor is assumed. The only thing it does is calling parent classes constructors (in this case none).

You can have many instances of an object this way. Example:
</code>void foo()
{
EnergyBolt *bolt; // 0

bolt = new EnergyBolt(); // 1
use_somewhere(bolt); // 2
bolt = new EnergyBolt(); // 1
use_somewhere(bolt); // 2
bolt = new EnergyBolt(); // 1
use_somewhere(bolt); // 2
}</code>
0 - create a pointer. No EnergyBolt objects yet.
1 - create EnergyBolt object, we have pointer to it stored in bolt
2 - use pointer somewhere, this procedure is responsible for placing the pointer in some safe location since we are going to lose it`s address (overwrite variable bolt).

If use_somewhere() won`t store the pointer then we have a memory leak since objects have memory allocated, but we don`t know where the memory (we`ve just lost all pointers to it and don`t know it`s location). Also there should be some routine that deletes these objects when they are no longer used.

As for the rest of code, I can`t understand it too. Maybe I`ll try to read it once more. :)

Korval
Quote:

Something that is confusing to me is the use of inner classes, maybe someone could explain that? I knew you can do it in java but I've never seen it done in c++ before. Why wouldn't energy bolt be a separate class?

Mostly for protection. Anyone #include-ing the header for SpellBolt can't start allocating EnergyBolt objects. It just prevents someone from hacking around the Spell-system.

C++ inner classes, btw, don't have a pointer to the class that they are defined in. Inner classes in C++ are purely for either logical grouping or for class protection, as I've used it for here.

Quote:

Isnt this implying that SpellBolt can only make 1 instance of EnergyBolt?

As I said, the comments are important:

The Comments said:

//Note that all Entity classes add themselves to
//the main entity list. They kill themselves when needed.
//There is no need to keep a pointer of these around.

'pTheBolt' is a local variable; it goes off the stack after creating it. So, if the above were not true, we would have just leaked memory.

Quote:

Now, for this vector, At the beginning of the program, I add all the different types of spell categories( as I assume SpellBolt is a category and not an actual spell)?

Bad assumption.

Look at my code. The Player::CastSpell takes a spell name. If that name isn't in the vector, then no spell is cast. As such all Spell instances that the Player can cast are stored in that object.

A category is a conceptual idea. Each spell could have its own individual class, or you could make it so that some spells have individual classes and others are all derived from a few classes that are mostly data driven.

Quote:

I just dont get the SpellBolt class and EnergyBolt class. If SpellBolt is an actual spell,
then why do we need EnergyBolt?

Because that's how I decided to do it. Classes derived from Spell only invoke the spell. Think of a Magic Missle spell. The spell itself only creates a homing missile; it is the missile that does damage.

Or, even better, think of a summoning spell. All the spell does is summon the creature. Once the creature is here, it's here; the spell is over the moment the creature arrives. It is a separation of the spell's invokation from it's effects (a create, a magical bolt, a visual effect, etc).

By doing this, you don't have to have a switch statement to pick a spell from a list; you just make spell classes and add them to the player's list. The CastSpell function, and the Spell's functions, do the rest.

Quote:

And is BoltSpell cast when the spell hits the target?

No. BoltSpell is just a different kind of spell. The SpellBolt fires an Entity that tracks the target. BoltSpell is an instantaneous spell. It displays a Sprite (a visual effect) and directly deals damage. BoltSpell relys on the Entity that it creates to do damage and any special effects when it hits.

SonShadowCat

I think im beginning to understand now. For SpellBolt and EnergyBolt, its the same as doing this:

class SpellLightning
{
  class LightningBolt : public Enitity

SpellLightning just creates the physical representation of the spell which is LightningBolt...ok, I understand now. And LightningBolt inherits say X_Pos, Y_Pos, Status, etc from its base Entity class right? Only functions in LightningBolt are the ones that are specific for that class?

I did ask this, SpellLightning is inherited from Spell right?

Now, in the InvokeSpell function, after I create a new spell instance, I should add it to the grand list/vector of spells that are currently active right? And then delete them as they hit targets, etc...ok.

For the BoltSpell class, SimpleSprite a class right?

james_lohr

gonna bookmark this thread - will be useful when I finally start using classes.

...I have to admit though, even after reading this entire thread, I'm still not convinced that classes are useful.

SonShadowCat

They are very useful, you'll find out when you start using them.

Korval
Quote:

I'm still not convinced that classes are useful.

Really?

Take the Entity class I was mentioning. Such a class does not need to be added to an Entity list manually, because every instance allocated will automatically put itself in that list. This is because the Entity constructor adds the Entity to the list. That way, you are guarenteed that all Entity objects are managed properly, because the constructor is always guarenteed to be called.

SonShadowCat

1 more question( aside form theones I ask in the last post), why do new EnergyBolt() and not new EnergyBolt?

Dont they both do the same thing?

ImLeftFooted
James Lohr said:

I'm still not convinced that classes are useful.

if for no other reason, classes are at least useful for defaulting values:

typdef struct cord{int x,y;}cord; //I'm really unfamilar with C, is this right?

//usage
cord player;
player.x = 0;
player.y = 0;

class cord{
public:int x,y;
cord() {x=y=0;}
};

//usage
cord player;

I like to think of classes as smart variables, until they get complicated anyway. then they're a bunch more.

edit:
say for example you wanted a variable that cant go below 5 or above 15

1class fi_int{
2private:
3 int var;
4public:
5 m_int() {var=5;}
6
7 void setVar(int v) {if(v<=15 && v>=5)var=v;}
8 int getVar() {return var;}
9};
10 
11//usage
12fi_int special_num;
13special_num.setVar(10);
14special_num.setVar(2);
15 
16getVar() == 10

you could go even farther and operator overload it

1class fi_int{
2private:
3 int var;
4public:
5 m_int() {var=5;}
6
7 void setVar(int v) {if(v<=15 && v>=5)var=v;}
8 int getVar()const {return var;}
9};
10 
11fi_int &operator=(fi_int& f, int v){
12 f.setVar(v);
13 return f;
14}
15 
16bool operator==(const fi_int& f, int v){
17 if(getVar() == v) return true;
18 return false;
19}
20 
21//usage
22fi_int special_num;
23special_num = 10;
24special_num = 2;
25 
26if(special_num == 2)//it doesnt
27if(special_num == 10)//it does!

ok, im probably getting way too complicated way too fast.. but, i think it shows some uses of classes, does it not?

edit2: whoops forgot to return the fi_int in operator=

Korval
Quote:

why do new EnergyBolt() and not new EnergyBolt?

Just my syntax. I usually put the parenthesis on objects I allocate.

james_lohr
Quote:

I'm still not convinced that classes are useful.

Sorry about the troll. I was just trying to prompt a few replies that would make the thread even more useful ;). Worked quite nicely indeed ;D.

Krzysztof Kluczek

I think, everything mentioned above can be done nicely in pure C too.

Creating Entity:

1Entity *new_Entity()
2{
3 Entity *ent = malloc(sizeof(Entity));
4 
5 // if most of the variables are 0 you can do this:
6 memset(ent,0,sizeof(*ent));
7 
8 // and other variables
9 ent->pos.x = 1;
10 ent->pos.y = 1;
11 
12 // put it into game logic
13 add_entity_to_list(ent);
14 
15 return ent;
16}
17 
18// code creating entity has the same complexity now
19Entity *e = new_Entity();

And smart variables:

void set_5_15(int *var,int val)
{
  if(val<5) *var=5;
  else if(val>15) *var=15;
  else *var=val;
}

// and usage:
set_5_15(&variable,value);

// or simplier using one of Allegro defines
variable = MID(5,value,15);

In fact, variable setting code looks really nice in C++, when operator = is used. The only problem is that operators are quite nice source of bugs. I made some time ago a class that implemented very large number`s operations with a bunch of operators including int conversion operators. As a result, when I was adding these numbers, they were converting to ints, adding up, and then converting to large numbers back! :P

I think, C++ operators and templates are quite useful, but when I don`t need these I write in C (but still using references, new and delete from C++).

Thread #333282. Printed from Allegro.cc