TT6: Simplify stat tracking with a std::map

This post is a technical post on how I put together stat tracking for Isotower, for the goals system.

A few days ago, I decided to add goals, or missions, or tasks, or quests to Isotower. I don’t have a name for them in the game, but in the code, they’re goals. Essentially, each goal would track a few stats, like how many people of a certain social class were in the tower, or how many rooms of a certain type were built, or how much money was being made per day, or per week. I was already tracking a lot of these stats, but they were often in their own variables stored in factories, or in the finance code. Writing code to look up this information in an easy way would get complicated if each stat had to have a different function pointer, or if there had to be a giant switch/case statement to know which stat pointed to which factory function. Pointers could have worked, and been fast, but there still would have been a need for a switch/case statement to know what to point to for each part of the goal.

Instead, I created a very simple factory to store a collection of stats, and used a std::map<std::string, double> to store everything. Double because finances and averages would be tracked, as well. This lets me store each stat as a std::string for the goals, and then simply look up the value in the StatTracker data to see if the goal has been reached. The code for the goals is easy to use and understand, I can track stats simply by simply calling StatTracker::INSTANCE().addValue(“new stat to track”); and it all ends up working smoothly. The final code came out to 4 public functions, and a mostly used for debug toString() function. The code is pasted here, because why not.

StatTracker.hpp
#ifndef _STAT_TRACKER_HPP
#define _STAT_TRACKER_HPP

#include <map>
#include <string>

class StatTracker {
private:
 std::map<std::string, double> stats;

 StatTracker();
 StatTracker(StatTracker const&);
 void operator=(StatTracker const&);
public:
 static StatTracker & INSTANCE();

 void addValue(std::string);
 void setValue(std::string, double);
 void changeValue(std::string, double);
 double getValue(std::string);

 std::string toString();
};

#endif
StatTracker.cpp
#include "source/Managers/StatTracker.hpp"

#include <sstream>

void StatTracker::addValue(std::string index)
{
 this->stats.insert(std::pair<std::string, double>(index, 0));
}

void StatTracker::setValue(std::string index, double value)
{
 this->stats[index] = value;
}

void StatTracker::changeValue(std::string index, double value)
{
 this->stats[index] += value;
}

double StatTracker::getValue(std::string index)
{
 return this->stats[index];
}

std::string StatTracker::toString()
{
 std::stringstream temp;

 for (const auto &pair : this->stats)
 {
 temp<<pair.first<<": "<<pair.second<<".\n";
 }

 return temp.str();
}

StatTracker::StatTracker() { }

StatTracker & StatTracker::INSTANCE()
{
 static StatTracker instance;

 return instance;
}

69 lines in total (25+44). Much easier to use and understand.

Sidenote: I use this singleton pattern in almost all the areas of my code. It might not be the “right” way to program things, but it’s easy to use, and at the moment, it does what I need.

TT5: Adding an interface

In the past few weeks, I’ve been working to add more depth to the game, and finished up some of the major systems. The biggest set of changes has been with the rooms, switching up how they worked internally, and solving a few problems along the way.

At the moment, the first thing needed is a construction office. It’ll hire construction workers to build the rest of your rooms. Only one construction worker can be dispatched to a newly built room at a time from each individual construction office, but building more offices can speed up the process of building a new room. Once rooms are built, they’ll have various requirements before people will rent them, or show up to shop at stores or eat at restaurants. Hotel rooms can be rented out, but will get dirty once everyone has left for the day, so they’ll need to be cleaned regularly. Security personal will occasionally need to be dispatched to rooms in case of threats. Rooms have a variety of factors that go into keeping high rating, from surrounding noise and beauty levels to how happy their tenants are, to how much money they’re making per day.

 

The interface for querying a room
The interface for querying a room.

There are still plenty of systems and other things to add and improve upon within the game. However, most of the major functions of the rooms are in place, so today, I’ve begun working out the interface layout that shows up when you query a room (seen above). This is not final (it needs a fair bit of work, obviously), but it contains all of the information about the room that the player will need. the red to green rectangle is the rating indicator, which will provide more detailed information when the player hovers over it. The three buttons will turn into tabs (defaulting to showing the info panel), and the info panel contains details from the income of the day and current rent price to how old the room is and “thoughts” which are more like messages from the room itself (and where you can find out if you’re missing a requirement or similar things).

 

The interface in the wild of the full game window.
The interface in the wild of the full game window.