Welcome! Log In Create A New Profile

Advanced

Adding Achievements

Posted by owen 
Adding Achievements
October 10, 2012 05:43PM
So I recently published my asteroids clone and I am thinking of adding achievements for ex. destroy 6 asteroids without getting hit or get a 200 asteroid combo with the default weapon in 2 minutes without getting hit. Something like what the MW3/COD games do in multiplayer. Is there a easy way to do this? is it worth doing?

I've been researching online and all roads point to [en.wikipedia.org]
Re: Adding Achievements
October 24, 2012 01:31PM
Yes, there is an easy way to do it. You generate statistics data while your game is running. You know when you destroy an asteroid, you know when you get hit, you know what weapon and for how long it's being used. So you just need to collect that data internally and query if any individual or combined statistics matches any of your predefined achievements.
Re: Adding Achievements
October 24, 2012 05:38PM
Thanx. I figured it out eventually. I created a big array of int[]. Then I created another array with the relationships between the int[]s. Then I create functions add(), reset(), check(). Whenever an add()/reset() event happens on a value I use the relationships to do a cascading update on the other values. Works like a dream. With no drop in frames.
Re: Adding Achievements
October 24, 2012 10:46PM
Quote
owen
Thanx. I figured it out eventually. I created a big array of int[]. Then I created another array with the relationships between the int[]s. Then I create functions add(), reset(), check(). Whenever an add()/reset() event happens on a value I use the relationships to do a cascading update on the other values. Works like a dream. With no drop in frames.

If you want, you could do it in a perhaps more efficient way.

Consider what happens if an asteroids session runs for long enough. Will your large array be filled? What if a session runs for only a short period of time? Then, you might have allocated a lot of memory that is never being used? (I know that this does not affect the framerate for your game, but it is good programming practice not to use more resources than you need. For example, if you ran this program on your ordinary computer with a bunch of other programs running alongside it, then you may not want to waste all that memory so that other programs can make use of it instead. Or what if you in the future want to add a bunch of features to your program that requires lot of memory, then you wouldn't want to be limited by an array that unnecessarily consumes tons of memory.)

So, I suggest you could use a data type which allocates memory dynamically, i.e. when it needs it. For instance, std::vector is implemented as an array that automatically resizes itself when it needs to and will never allocate more than a small constant times the memory you use. The downside of using a vector is that these reallocations might be quite time consuming if the array becomes large enough. If this turns out to be a problem, you could consider using maybe an std::deque instead, which is essentially a vector of arrays (at least the gcc 4.4.5 implementation is) and for which these slow reallocations would occur for far greater memory sizes. Also, if you don't need efficient random access for your data type (that is, being able to access any element of the array quickly), you could consider using std::list. std::list will not allocate any memory that is not being used and has no time consuming reallocations which the other two data types I just mentioned might suffer from, but instead allocates memory in the moment you add elements to it.

Note that this improvement is just a suggestion (obviously)! :D

edit: reformulation



Edited 2 time(s). Last edit at 10/24/2012 10:49PM by profetylen.
Re: Adding Achievements
October 25, 2012 10:40AM
just adding my 2 cents to profetylen's suggestion:

There's only a limited number of players, so it should be determinable how much memory you need to use in advance.
While I use STL-like containers myself all the time, I would advise to avoid per frame memory allocations at all costs in a game. So when you use std::vector, you should resize it to the needed capacity in advance in order to avoid reallocation during runtime.
Re: Adding Achievements
October 26, 2012 05:43PM
@profetylen suggestions are always welcome! especially since it a ghost town around here. but allocating dynamic memory at runtime may be more trouble than it is worth. I have a fixed amount of achievements (25) and a fixed amount of statistics (100) - no need for dynamic memory when I already know what my limits are. Also when the player quits the game I have to save/load all that information to disk which makes you dynamic memory solution even more troublesome.

Currently I have an array of size 100 and I am tracking 60 + stats in a single player game;
	#define STAT_DISTANCE 1	
	#define STAT_DISTANCE_TOTAL 2

	#define STAT_MOVE_FORWARD 5
	#define STAT_MOVE_TURN 6
	#define STAT_MOVE_BACK 7

	#define STAT_SHOT 8
	#define STAT_SHOT_TOTAL 9
	#define STAT_SHOT_ALT 10
	#define STAT_OVERHEAT 11
	#define STAT_OVERHEAT_TOTAL 12
	
	#define STAT_HIT 13
	#define STAT_HIT_TOTAL 14

	#define STAT_SECONDS_WITHOUT_HIT 15
	#define STAT_KILLS_WITHOUT_HIT 16
	#define STAT_DISTANCE_WITHOUT_HIT 17
	#define STAT_DISTANCE_WITHOUT_SHOT 18
	#define STAT_SECONDS_WITHOUT_OVERHEAT 19
	
	#define STAT_MINUTES 20
	#define STAT_SECONDS 21
	#define STAT_GUI_SECONDS 22
	#define STAT_SECONDS_TOTAL 23

	#define STAT_ACHIEVEMENT_TOTAL 25
	#define STAT_ACHIEVEMENT_COMPLETED 26

	#define STAT_KILLS 30
	#define STAT_KILLS_ASTEROID 31 
	#define STAT_KILLS_ENEMY 32
	#define STAT_KILLS_TOTAL 33
	#define STAT_KILLS_ASTEROID_TOTAL 34 
	#define STAT_KILLS_ENEMY_TOTAL 35
	
	#define STAT_BULLETS_FIRED_TOTAL 36
	#define STAT_SECONDS_WITHOUT_KILL 37
	
	#define STAT_CURRENT_GAME 40
	#define STAT_DEATH_TOTAL 41

	#define STAT_COINS 50
	#define STAT_COINS_TOTAL 51
	#define STAT_COMBO 52

	#define STAT_KILLS_WITH_BULLET_DEF 60
	#define STAT_KILLS_WITH_BULLET_MGUN 61
	#define STAT_KILLS_WITH_BULLET_LASER 62
	#define STAT_KILLS_WITH_BULLET_SPREAD 63
	#define STAT_KILLS_WITH_BULLET_BURST 64
	
	#define STAT_KILLS_WITHOUT_OVERHEAT 70
Re: Adding Achievements
October 27, 2012 12:32AM
@owen:

Oh! I didn't realize you had a constant amount of statistics! So, I guess the way you do it is just fine!

Glad to hear suggestions are welcome, and when I saw those #defines, I'm gonna give you another one. Why don't you use a struct instead? I guess that would be a tad more manageable and clean than an array (not that an array is particularly unclean or unmanageable, but since you were open for suggestions, I figured I could give you another one).

Also, just to be sure; those are indexes to the to array, right? So you access your statistics by something like statsArr[STAT_DEATH_TOTAL], right? In that case, I wonder why you start at index 1 and not index 0.
Re: Adding Achievements
October 27, 2012 04:21AM
It doesn't really matter if I have unused slots in my array. I keep the unused indexes there in case I think up a new statistic that I want to track then I could just put it into a slot that is close to similar stats (otherwise I would have to add it to the bottom of the list). All the statistics are integers - no other data is needed at the moment - it would be a struct with only a int value. I used structs in other places for storing the many-to-many relationships between 2 different statistics.
Re: Adding Achievements
October 30, 2012 09:50AM
Owen,

generally speaking, unused slots in an array means suboptimal use of the data cache. I'd use a struct like profetylen suggested, as it would be more compact and manageable (no need to deal with those numbers, so no need for unused slots that are just there for future extensibility. You need a new stats attribute, you just add it to the struct).
Re: Adding Achievements
October 30, 2012 02:33PM
@antibyte when I just started researching the topic one website suggested that I set up a class for each type of statistic then look them into an list structure. The unused slots in a static array are there for future use, especially since an array of int[100] is probably the smallest piece of data that I have in the whole game. No heap searching or looping when looking up information, no pointers, hooks or listeners, its all direct access.

if I want to know the value of a statistic I call the check function;
int statistic_check(int ind){
	return statistic_list[ind].int_value;
}

if I want to know how many times the player died I do this;
if( statistic_check(STAT_DEATH_TOTAL) > 20 ){
//do something
}
Re: Adding Achievements
November 03, 2012 01:15PM
Also note that there are 3 parts to the whole system.

The statisics; collects the stats required to determine if the achievement is completed.

The achievement engine; stores the name and description of each achievement and the combination of stats that are needed to to complete each one. This is also an array but can be a dynamic structure.

The display engine; if you going to have in game alerts you will need to track the moment when an achievement is complete and show a message. This message must show up only once and must persist as long as needed. There are also cases when multiple achievement appear at the same time so the engine should be able to stack the popups so the player does not miss an alert.
Sorry, only registered users may post in this forum.

Click here to login