gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Beginners > Achievements

#172299 - Azenris - Fri Jan 29, 2010 4:36 pm

I wanted to create an achievement system and wondering whats a good way to go
about it. I was thinking of something like

Code:
class CMedal
{
   // func: Virtual Update(const CEvent &event) = 0;

   // var: name
   // var: description
}


Code:
class CMedal_1 : public CMedal
{
   CMedal_1 () : CMedal("Shopoholic", "Visit the shop 5 times") { }

   // func: Update(const CEvent &event)
       // check for 5 entires into the shop

   // vars: any specific counters to this medal
   // eg:    count events EVNT_ENTERED_SHOP
}


Code:
class CMedal_2 : public CMedal
{
   CMedal_2 () : CMedal("Bruised", "Take a total of 1000 damage in a game") { }

   // func: Update(const CEvent &event)
       // check for 1000 damage total taken
       // check for end of game (EVNT_GAME_FINISHED), clear damage var

   // vars: any specific counters to this medal
   // eg:    count damage taken
}


Code:
void Init_Medals(void)
{
   medalList.push_back(new CMedal_1);
   medalList.push_back(new CMedal_2);
}


and then within the event system whenever an event is called
loop the medals passing the event as an arguement.

Also I was thinking of having a seperate list of actively watched medals, only those would be called.
For example have a medal type MEDAL_TYPE_OUTOFBATTLE, all those types of medals would be
loaded when out of battle and the rest ignored. This would also allow me to not bother calling
already completed medals.

I dunno does this sound OK, what other possibilies could I explore for an achievement system?
_________________
My Homebrew Games

#172302 - Drovor - Fri Jan 29, 2010 5:19 pm

Your approach looks like it would work fine to me, it implies your already keeping a bunch of statistics. If you are it makes sense to use them.

Another method that might fit nicely is the Observer pattern. Have each medal observe whatever is in charge of what the medal is for (i.e. Medal1 observes the shop class, Medal2 observes the player)

Then each medal can keep tabs of its specific criteria, such as Medal2 resetting at the beginning of a level and being unlocked at the end.

This might allow for more granularity, like if you wanted to have a medal for killing 10 enemies in 10 seconds, you might not want to add timer handling to the stats class but it would be trivial to add to a medal class that receives combat events.

#172311 - sgeos - Sat Jan 30, 2010 7:50 am

I'd have a statistical tracking container that takes care of the updates, and have the medals poll that as necessary. This is neither here nor there.

FYI, you can do neat things with dynamic names and descriptions. For example, you could have a "Pacifist" medal morph as you kill enemies.
In pseudocode (there are better ways to do this):

Code:
message name()
{
  int kills = statistics.getKills();

  if (kills == 0)
    return MSG_PACIFIST;
  else if (kills == 1)
    return MSG_FIRST_KILL;
  else if (kills < 5)
    return MSG_SELF_DEFENDER;
  else if (kills < 100)
    return MSG_ATTACKER;
  // else (100 <= kills)
    return MSG_VETERAN;
}

message description()
{
  // Will read "Killed 45 enemies.", if 45 enemies have been killed.
  return MSG_KILLED_X_ENEMIES;
}

// For event scripting
bool isPacifist()
{
  int kills = statistics.getKills();
  return (kills == 0);
}

#172320 - Azenris - Sat Jan 30, 2010 4:16 pm

Thanks for the replies :)
_________________
My Homebrew Games