Moments of Inertia by Rachel Crawford

About     Archive     Categories     Tags     Feed     Projects     Podcast Recommendations    

The Hobby

Saurus warrior

Reader, I paint lizards.

I paint them at the weekend. I paint them on weekday evenings. Sometimes I even paint them before going to work. Painting lizards is my new, engrossing pastime.

Part of that was a lie: it’s not really a new interest, but a revived one. The world of miniatures has drawn my attention since I was little, but I drifted away from it in my mid-teens. In the last few years I’ve experienced a growing desire to get back in, spurred on by the enthusiastic evangelism of podcasts like Miniatures Monthly and websites like Hipsterhammer.

Feeling inspired, I dug my old Warhammer models out of the eaves in my mum’s house, dusted them off, and surveyed what I found. It was a wasteland. Many were unpainted and others were painted so poorly that it almost seemed cruel not to repaint them. Which was perfect. It means I have a treasure trove of miniatures to practice on before I need to get new models.

Skink skirmisher with blowpipe

Ever since then I’ve been steadily working my way through them, painting or re-painting a few every week. The majority are Lizardmen (now dubbed Seraphon in the Age of Sigmar system that replaced the crotchety Warhammer Fantasy Battle a few years ago), but there are some Eldar, Lord of the Rings minis, and a mixed bag of others. There’s even an unassembled Space Marine tank which I have no recollection of acquiring.

I find painting highly rewarding. It’s as if the activity is opens my head up and fixes all the faulty wires. When I emerge from a session, I feel calm and energised. Since starting I’ve improved measurably and am already a better painter than child-me ever was. It’s been a joy to watch my skills sharpening as I practice and my knowledge growing as I experiment, consume tutorials, get tips and ask questions.

When I need advice, there’s a channel on The Crate and Crowbar’s Discord server which I’ve found to be a great place to hang out and share my progress. The level of skill on display in there can be astonishingly high – a little intimidating, even – but the welcoming attitude of all the patrons means my questions are always answered helpfully and considerately. I also enjoy the painting tutorials on Warhammer TV.

Old-school Bretonnian archers

Things are different now. The hobby itself is in flux, riding the wake of the recent tabletop games renaissance. Games Workshop are smarter about technology and community-building than I remember they used to be, and it seems to be paying off. They’re also experimenting with more board-gamey designs like Shadespire1, while Fantasy Flight are making inroads into the miniatures wargaming space with their own recent titles. Elsewhere on the landscape, neat-looking games like Frostgrave are making me want to grab some dice and dive in.

I also feel like the hobby is becoming a better place for women. I hope I don’t have to eat those words.

Climate change aside, the biggest difference between then and now is that I have an adult’s patience and a full-time employee’s disposable income. This thing demands a lot of time, dedication, and money. I’m glad I have them.

Thanks for reading! Have you had experiences with the hobby? Tell me about them on Twitter or in the comments below.

  1. I’m really enthusiastic about Shadespire and have been playing about 4 games of it per week since it came out. It’s excellent. If I’m lucky I’ll get post about it written sometime. 

Ding! 24

I turned 24 today. This weekend has been a bit busy and overwhelming – but perfect.

On Friday I went to Dundee for some Marioke, which was fantastic. The event itself was amazing, but it was also nice to see some Dundee friends I hadn’t met for a while. Hopefully we’ll have another Marioke in Scotland some time.

Last night we had some friends over for a flat party. My flatmate had decorated the whole place in birthday stuff while I was out during the day (at edindies, in fact). That was a lot of effort I didn’t expect anyone to take, but really appreciated. She also got me a cake!

Natalie made me a birthday card in short game form, which was incredibly sweet. I’m really grateful for her.

Today I had lunch with my mum and I’m meeting my dad for dinner. It’s nice to see them both, as usual.

I’ve been barrelled over by all the folks who have checked in and said happy birthday, over the internet or otherwise. It’s not that there’s been more than usual, it’s that I seem to be paying attention to it more. I think for a number of years I haven’t really noticed birthdays – in fact last year I thought I was turning 22, not 23 – but this year has been different for some reason. Maybe it’s just that some things kind of settled into place this year? Who knows.

Anyway, thankyou for being along for the ride. Here’s to another year of us.

New Page: Podcast Recommendations

I’ve added a new page to the website containing a few podcasts I regularly listen to, or have listened to in the past, that I think are good and want to share with people. At the moment there’s only a handful. I’ll update it with new ones occasionally.

Check it out.

Custom Deleters: A Real Example

I’ve written in the past about standard-library smart pointers and how they can make management of memory allocated from the heap much easier. How useful are they when working with objects allocated from elsewhere, such as objects created by a library we use?

Box2D is a popular 2D rigid-body physics engine in which the b2World is the top-level object that represents the physics ‘world’. Rigid bodies are represented by instances of b2Body and are created like so:

// world is a b2World*
// bodyDef is a b2BodyDef that describes the properties of the new body
b2Body* body = world->CreateBody(&bodyDef);

The b2World owns the b2Body and the memory it is created from, and when the world is destroyed it destroys all the bodies it contains. To remove an individual body and free its memory we call b2World::DestroyBody(b2Body*).

This creates a small challenge for us when we build our game code on top. Let’s say we have an Entity class, which has a b2Body* member.

class Entity {
  b2Body* body;
};

In Entity’s destructor we may want to call DestroyBody, so that when an Entity goes out of scope, it tells the b2World to remove its body from the world:

Entity::~Entity() {
  if (body) body->GetWorld()->DestroyBody(body);
}

These are unique ownership semantics (just about), so we could make body a std::unique_ptr rather than a raw pointer. Let’s try it!

std::unique_ptr<b2Body> bodyPtr = world->CreateBody(&bodyDef);

Unfortunately, this is no good. By default, std::unique_ptr’s destructor calls delete on its internal pointer, which isn’t what we want. The b2World is who really owns the memory, so deleting it out from underneath it would probably cause undefined behaviour down the line, if not immediately. The memory which the b2World allocates bodies etc. from may be a pool block-allocated from the heap. It might not even come from the heap, it may be on the stack. Either way, calling delete on a bit of it would not go down well.

So we need to call b2World::DestroyBody instead of delete.

Custom Deleters

We’re in luck: std::unique_ptr has more than one template parameter.

template<class T, class Deleter = std::default_delete<T>>
class unique_ptr;

The first is the type to which it points, and the second allows the user to define a custom deleter. A custom deleter must be a type with an operator that takes a pointer to T. The custom deleter lets us define what unique_ptr’s destructor does if its internal pointer is non-null.

Here is a pointless example of one that just does the same as std::default_delete<b2Body>:

struct b2BodyDeleter {
  void operator()(b2Body* body) const {
    delete body;
  }
};

using std::unique_ptr<b2Body, b2BodyDeleter> BodyPtr;

BodyPtr = world->CreateBody(&bodyDef);

Obviously this isn’t what we need because we need to call b2World::DestroyBody.

Gotcha

A quick aside, and a warning – you might be wondering why we can’t just use a regular ol’ free function for this. Here’s why.

void b2BodyDeleter(b2Body* body) {
  delete body;
}

using BodyPtr bp = std::unique_ptr<b2Body, b2BodyDeleter>;

BodyPtr doesn’t compile because b2BodyDeleter isn’t a type - it’s a function. Using decltype and an ampersand, we can proceed:

using BodyPtr = std::unique_ptr<int, decltype(&b2BodyDeleter)>;

decltype(&b2BodyDeleter) gives us the type of a pointer to the b2BodyDeleter function (which I’m not going to write, because ugh). However, when we try to instantiate BodyPtr we hit a snag – the class doesn’t have a default constructor anymore, and must be constructed with a pointer to b2BodyDeleter (or any function with a matching signature, actually – so much for safety!).

BodyPtr body; // Doesn't compile!
BodyPtr body(nullptr, &b2BodyDeleter); // Does compile!
BodyPtr body(world->CreateBody(&bodyDef), &b2BodyDeleter); // Does compile!

Unfortunately, BodyPtr is no longer a zero-cost abstraction as it now consists of both a pointer to a b2Body and a function pointer.

static_assert(sizeof(BodyPtr) == sizeof(b2Body*)); // Fails!

If we instead use a functor like our original b2BodyDeleter then the empty base class optimization allows unique_ptr’s size to equal the size of a raw pointer. When using a function pointer our smart pointer becomes stateful, meaning it carries additional stuff along with its underlying raw pointer. This is a bit of a gotcha, and arguably things shouldn’t have to be this way (i.e. functions in C++ should be first-class types), but writing a functor or a lambda to avoid this isn’t too much bother.

b2BodyDeleter

So finally here’s our real b2BodyDeleter:

struct b2BodyDeleter {
  void operator()(b2Body* body) const {
    body->GetWorld()->DestroyBody(body);
  }
};

using BodyPtr = std::unique_ptr<b2Body, b2BodyDeleter>;

static_assert(sizeof(BodyPtr) == sizeof(b2Body*));

BodyPtr body = world->CreateBody(&bodyDef);

We had a choice here. Instead of accessing the b2World using b2Body::GetWorld we could store a World* (or World&) in b2BodyDeleter, setting it in the constructor. That doesn’t really bring any advantages that I can think of, and I can think of two disadvantages. For one, it would force us to specify an extra argument every time we instantiate a BodyPtr. For another, it’d make the deleter stateful and increase its size. No good!

Now we can swap Entity’s raw b2Body pointer for a BodyPtr, and we never have to worry about manually calling b2World::DestroyBody for the Entity’s body again. The body will be removed from the world when the Entity goes out of scope. We get all the other benefits of unique_ptr, too.

There are limitations to doing things this way: an Entity now must go out of scope before the b2World does, otherwise b2Body->GetWorld will return a dangling pointer. We can no longer destroy the b2World before all the Entity instances who are using it unless we call release on each Entity’s BodyPtr before its destructor is called.

This example may seem like a bit of a strawman to you, but in my homebrew game engine switching from using raw b2Body pointers to smart ones has been a pleasant improvement. It fits into my RAII-based approach to just about everything.

Further Reading

Fluent C++ did a series about smart pointers recently, with a few posts dedicated to custom deleters:

La Garde-Freinet (30th September - 8th October)

Recently me and Natalie went on holiday for a week in the south of France. We stayed in an old townhouse in La Garde-Freinet, a village nestled in the hills above Saint-Tropez, with my mum and her partner.

I’ve been there a few times before but not for about five years. It was good to be back. It’s a lovely, pleasant and peaceful place; the perfect retreat. In many ways it’s just as I remember, but in October it has a rather different feel than it does in summer, during which I’d previously visited. Many of the shops and restaurants are beginning to close down for the winter when there is too little business for it to be worth opening, and generally it is a bit quieter in the absence of high-summer holiday traffic.

The surrounding countryside is densely forested and the hills are low enough to be covered all the way to their peaks in a foliage, giving them an almost fuzzy appearance. Autumn hasn’t quite arrived yet and everything is lush and verdant, if a little dry. On the plains to the north and south the forest sprawls, giving way only to roads, groves, villages and vineyards. Big umbrella pines tower over smaller deciduous trees, bushes and shrubs. The earth is the colour of rust, visible between blades of dry, brittle grass.

The region is a historic producer of silk, chestnuts and cork, and it still exports the latter two. Along the edges of paths one can find trees that have been stripped naked of all their bark up to about head height, and chestnut trees are abundant.

We spent the week going for walks in the village and the area, relaxing, eating and sleeping. It was great to spend so much time with Natalie.

We made a day trip to the Gorges du Verdon, a truly awe-inspiring landscape. Vultures circle above brilliant white crags between which, hundreds of metres below, flows a sliver of pure turquoise. Every bit of land that isn’t vertical is blanketed in foliage, now breaking out into autumn colours. We drove along the top of the gorge, taking in the vistas, then followed the road down into it, clinging to the sides.

After emerging from the gorge’s mouth, which opens onto a long ice-blue lake, we visited the village of Moustiers-Sainte-Marie. It too is a stunningly beautiful place, old and quaint and majestic all at once. Above of the village, atop a long flight of steps, perches an old chapel, which we made the climb to visit.

Then, leaving the village, we rented a pedalo and took it back into the gorge, gaping at the scale of the thing, peddling past weird rock formations and strange caves. If you ever find yourself in the region, I highly recommend checking it out.

Also, I drank multiple cups of wine every evening. It was great.