Category Archives: devblog

New Service: Godot Tool and Game Development

I’m pleased to announce that I’ve been able to get deep enough into Godot development at this point to feel comfortable offering development in the engine as part of my service profile.

Godot joins Unity and Unreal as well as bespoke development as a core Perfect Minute service offering. If you’ve got game development needs and want to use Godot for your engine, I’d love to have a chat!

CMF 6: The Process

This post is part of a series for game developers applying to the Canada Media Fund.

So far this series has mostly talked about different aspects of applying to the CMF for project funding. Today I want to talk about what happens after you’ve gotten a project accepted.

The (Not So Secret) Agent

When you submit an application to CMF, you are assigned an agent. That person is your go-between for the application, and my experience has been that they’re delightfully helpful. Every time I wasn’t sure about something, I could send a question to the CMF agent and they’d get back to me in a couple of days with helpful information.

Here’s an example: I didn’t have payroll set up for Perfect Minute when I was getting ready to start work for Conceptualization. Getting an employee agreement was going to cost me several hundred dollars and possibly a couple of weeks waiting on my lawyer for the agreement. I’d committed to a start date that came earlier than I could possibly get those details sorted out, and so I asked the agent if I could act as a contractor until I had my employment agreement figured out. They indicated that this was highly irregular and not recommended, but in the end they helped me figure out how to bridge that gap.

Maybe that doesn’t sound like much from the outside. But the contract you sign with CMF has a bunch of clauses that basically say if you do anything shady they’re going to pull your funding. That’s not unusual on its own – any business contract is likely to include language that allows either party to exit in certain circumstances – but if you’re not familiar with the other party, or if you’re relatively new to contracts at this level, it can add a lot of stress. Having someone to help you navigate is a big deal.

Program Phases

It’s also important to note that each CMF program is divided into two or more phases. For Conceptualization, the program has just the two phases – Phase I covers your initial estimated costs and plan, and Phase II is your final, actual costs and plan. There’s money riding on getting the documentation for each phase correct.

This gets more complicated when you’re doing one of the production programs; those use three or more phases, with a “beta” delivery in the late-middle part of the development schedule. It’s not so different from how publishers use milestones, but having dealt with a few milestones from both the dev trenches and the managerial towers, they’re tricky.

Things can change really fast in game development, and if what you deliver to someone for a milestone is not what they expected, you might forfeit an expected milestone payment. I haven’t had that experience with CMF, but I’ve had it in other circumstances, and it can be absolutely crushing. Project-killing, even.

It’s important, then, to communicate when changes happen. I asked for several schedule extensions during the course of our Conceptualization work, as it became obvious that certain assets just wouldn’t be ready, and as we realized that some of the early decisions we’d made weren’t working as well as we’d hoped, requiring significant rework and direction shifts. And to their credit, CMF accommodated. The agent eventually came back and said listen, you’ve committed to all documentation by July, so just make sure you’ve got it all in by then.

For me, July wasn’t really an option – I have a day job, after all, and I can’t indefinitely dedicate the 20+ hours a week I was spending over the last four months to a second job – but that took some pressure off all the same. We delivered our final docs a couple of weeks ago, and there’s been a little back and forth since then, but ultimately we were approved on Phase II.

About That Back and Forth

One of the things I personally was paranoid about when I was getting into the CMF’s orbit was my own lack of expertise in business. I was convinced that messing up documents and information would turn into an endless problem full of legal nightmares.

Nothing could have been further from the truth, however. Both during my applications and afterwards, I’ve been able to get detailed feedback on problems with my documents and information, submit amended versions, and see positive results.

I’m sure there’s a threshold below which the agent just can’t help, but thankfully ours was very ready to assist, and our documentation only needed a few changes to meet the requirements. It was encouraging to realize that this was how they do things.

Graduation

The other thing that I appreciated during all of this was that the CMF’s Experimental program portfolio is designed to feed forward. When you submit your final documentation for Conceptualization, for example, they ask if you’re applying for any other programs.

We are, of course. I’ve already talked about the application we submitted to the Innovation & Experimentation program, but it was nice to know that there’s a built-in way to tie the two together. I feel confident that what we submitted shows us in a good light. If we can put together what we did with $20,000, it’s natural to believe we could do a lot more with a larger investment.

I’m excited at the idea, though truth be told I have no idea where I’d come up with our 25% right now. I’d hoped to avail of traditional (debt) financing, but so far that’s coming up empty. There’s the possibility of a Kickstarter, but these days those require a level of readiness and polish that exceeds the grasp of the average unfunded developer who nonetheless has to pay mortgages and keep life and limb together.

Maybe we’ll figure it out. Given we don’t yet have a demo or an approved application, it’s somewhat moot at the moment. But it’s important to be prepared.

On that note…watch this space for news in the days and weeks to come. Our little Action-Painting-Strategy RPG still has some legs yet.


Featured Image

Contracts” by NobMouse is licensed under CC BY 2.0.

Paint By Monsters DevLog 7 – Design Process Part 1 – High Level Design (So Far)

Paint By Monsters started life, as with many of my original designs, as an attempt to subvert aspects of an existing popular design. In this case, it was the Horde Survival/Bullet Heaven microgenre, which has exploded in popularity since Vampire Survivors appeared on the scene.

This type of game is an attractive prospect for a dev – mechanically simple, technically and artistically feasible for a reasonably skilled development team, and with a reasonably short development cycle. If I had any sense, probably, I might have been content to simply create a much more direct version of the experience myself. But.

Originality in Replication?

I often take a contrarian stance in some aspect of a new design (witness the small squad sizes in Contension or the worst-of-both-worlds combination of cards and tiles in Mechanisms). I often end up thinking about how to “reverse” a particular a genre. In this case, I was thinking about “reverse horde survival”.

The obvious first step, for me, was inverting the relationship of player and entities onscreen. In Horde Survival, you are one against many, so obviously in the reversal you play many against one. This eventually became many against few rather than one, since there’s still action economy to consider, but the core idea remains the same – the player uses a horde of relatively weak minions to fend off a small band of powerful invaders.

This idea, on its own, is the same basic formula as Dungeon Keeper and its ilk. That’s not a bad thing – Dungeon Keeper was a lot of fun, after all – but one thing dungeon defense games don’t do all that well is the kind of continuous action that horde survival has perfected.

So how could we channel that feeling of “action” if mostly you’re just spawning hordes of autonomous creatures? Feature Demo 0.0.1 took a look at the simplest version: spawning minions in realtime. Nothing fancy, just skeletons appearing whenever and wherever you hold the mouse button down.

The next few feature demos built on top of this foundation – 0.0.2 added a little agency to the enemy, 0.0.4 added a win condition, 0.0.3, 0.05, and 0.0.6 added new enemy and minion types. The “minimum viable loop”, such as it was, seemed complete. And it felt…not great.

Player Experience

I knew why it didn’t feel great. Even with a bunch of minion types to switch between, even with limited numbers of each minion type, even with adventurers carefully tuned so you could just barely beat them if you did a good job with the resources available…you were just moving the mouse around with the button down. It didn’t feel intentional.

That’s when I starting thinking ahead, thinking about what the Player Experience should be. Player Experience is something that gets talked about a lot more in board game design than in video game design, in my (limited) experience, but it’s important in both.

It’s not really about the core loop, though that loop will inform it. It’s not really about the theme, though the player will form impressions based on the theme that will affect their experience. It’s not even really about the action economy itself.

Player Experience, at its very core, is the answer to “What do I want the player to feel while playing this game?” For Paint By Monsters, as it turns out, the answer to that question is: I want them to feel like an artist who uses their art to stand up against tyranny, the same way many artists I admire around the world have done throughout the ages.

Until this point, mind, I had no idea that was any part of what the game was about. I thought I was trying a new take on something that’s kept me creatively engaged for years. I wrote a book a while back set in a world where music and magic were the same thing. I was spending hours in that world nearly every day for 2 years, and at some point, I realized that in that world any art form should invoke magic.

Paint By Monsters was playing some of those same notes, and I kind of thought it was going in the same direction. But reading a story where some folks use art as magic, and actually playing the role of one of those folks, as it turns out, feels different. There’s a lot that comes out of that, but the big thing was clarity on a few different pieces of design:

  1. The Adventurers (who til now I’d sometimes been calling Heroes) were antagonists. There’s an easy perspective switch to make here – anyone with a little history in their head can appreciate how the crown and its servants might sometimes have dealt unkindly with common folk and upstarts in centuries gone by.
  2. The player should really feel like an artist while they play. Thus was born the notion of The Artist, the character represented by the player themself, and the Studio, the room in which they make their final stand in each life.
  3. Along with the Artist came Brush Strokes, which eventually became the basis of Feature Demo 0.0.10. It feels very different to just continuously spray minions into the arena, trying to surround and confound the enemy, versus using quick, precise strokes. It feels intentional.

These, then, are the cornerstones of the game’s core gameplay loop. We call it Room Painting.

Each new room is a new chance to try to stop the Adventurers from getting closer to the Studio. In each room, you channel creative energy to paint minions into the scene, and somewhere in the ensuing chaos one side or the other emerges victorious.

There are a lot of fun bits and pieces that have emerged from this core concept, and I’m looking forward to talking about those in future articles, but the emergence of these three key ideas, and particularly the Brush Strokes mechanic, was the first time I felt like I was headed for a good understanding of the Player Experience.

Art, Artists, Art Directors, and Beast-Headed Men

Somewhere around this time, I started talking to artists. I eventually landed on the incomparable Curtis Rioux and his merry band at Stellar Boar Studios. At first we talked solely about the studio doing art for the game, but as I went through the application process for CMF, I realized that games have many kinds of design intermingling, and art was an area where I really didn’t have the right skills or sensibility.

Happily, Curtis does have such a sensibility, and furthermore, when I sat down with him to talk about his ideas as Art Director for the game, he was already moving at the speed of thought. He brought a bunch of medieval mythical creatures to my attention, the best of which we chose for our starting lineup. I can’t wait for him to tell you all about the process of bringing those to life.

This new input set fire to my brain. I’d had a vague notion of what the world map might look like before, but adding these unusual creatures to the mix, along with a bunch of HEMA nerdery (check out Tod’s Workshop and Shadiversity in particular), gave me a strong sense of the tone of the game. There’s a playfulness here that wasn’t immediately apparent with the generic royalty-free assets I’d been using initially.

How can you not laugh at this guy?
Why is he wearing a padlock as a jaw strap?

I recognized, looking at these strange artifacts of ancient imaginations, that we’d do well to hold our tongues in our cheeks now and then.

Take Me to Your Action Heroes Murder Hobos

Maybe because of that new sense of levity, I also recognized that the game feels a bit like an Action RPG, and also that dudes who just run around with swords are Bo Ring. We needed a little flavour. A little flare. A little Michael Bay, if you will.

At this point I’d already worked on 0.0.7 & 0.0.8 (heavily informed by the excellent upgrade system in Brotato) and 0.0.9 (Dungeon Keeper, obv), and those informed my ideas about where we might inject some Action Hero notes. I also drew these:

This isn’t actually how it will go, but it inspired something all the same.
An early concept showing the Dandy swinging on a chandelier like Errol Flynn. Somehow, despite the diagonal lines, I thought I was making “pixel art” with this.

Just messing around with these sketches let me think in more concrete terms about what kinds of action might matter – interacting with the environment (particularly the addons from 0.0.9), the room, and the Minion horde. And that set me down the path to thinking about archetypes and Murder Hobos.

Murder Hobos is an idea in tabletop RPG circles that the group of characters in a typical D&D game is sometimes indistinguishable from a band of drifter serial killers whose sole purpose in life is to destroy life and steal property.

These days a lot of RPG players recognize that maybe this isn’t the healthiest model within which to run a roleplaying game, but for Paint By Monsters it fits perfectly.

The Adventurers are, after all the antagonists. It’s fine if they’re despicable. Better than fine – it drives home that whole thing about opposing tyranny.

And if the Adventurers are the expression of tyranny, then the ultimate realization of that is the crown itself. I’d already been thinking about including a traditional roguelike world map (sometimes called an FTL map), and putting Studio and Castle in opposition to one another fit very neatly into that setup.

This became the second loop of the game, which we’re calling Gauntlet Building. The player adds rooms to their magical gauntlet, trying to head off incoming Adventurers, and each time an adventuring party finds a room, they invade the gauntlet in search of treasure and glory, kicking off another iteration of the inner (Room) Loop (the one with the painterly gameplay).

There are, as with everything else, lots of fine details that have spun off from these seeds, and we’ll tell you more about those as development proceeds.

Roguelike? More Like Roguetolerate

The final piece of our puzzle is meta-progression. Folks often say this was the real secret to Vampire Survivors’ success, and it’s hard to disagree. The game makes you feel like you’re adding stacks on stacks on stacks on NUCULAR WEPPONS.

This is the second place in the design where my inner contrarian raised his head. Most roguelike games keep the the meta-progression elements behind very simple interfaces. A few have played with expectations a bit, or used more traditional unlock systems where completing specific in-game goals will open up new and exciting possibilities. But we already had such an interesting, unique world taking shape that tacking on the merest mechanical necessities felt really unsatisfying.

I started thinking about Evil Overlords and the tropes around them. Think about the villains in Lord of the Rings or Wheel of Time, for example – a dark lord is defeated, an epoch passes, a dark lord rises once again, ad infinitum.

Epochs

As a word nerd, any chance to use the word “epoch” is a chance worth taking, and so we came up with the Epochal Loop. The Artist may not be a dark lord, but they do rise and fall in the same age-old cycle.

Curtis (remember Curtis?) suggested that maybe in these sections of the game, the player is travelling between worlds, exploring an infinite universe of possibilities, and I thought that was just the best thing, for lots of different reasons.

Among those reasons is how it explains why the world we’re on is always in roughly the same technological period. Sure, civilizations rise and fall, but these days folks like to say History doesn’t repeat, but it rhymes.

We could say the roguelike elements of a game like ours – procedural worlds and progression, unlocked pools of randomly awarded abilities, cycles within cycles – fit this idea, but on some level it just feels better to say that maybe The Artist’s very soul is attuned to the medieval, and so when, in their travels, they happen across worlds upon which the people are just getting around to forging steel and fight senseless battles that will nonetheless inspire great art, they feel drawn to those worlds.

At least, that’s the backstory.

In Paint By Monsters, we call the place where the soul goes seeking its next home the Spirit World, and we’re building some unique gameplay around it. It will be a dark, mysterious place that lets you move at a slower pace – a good place to reset your mind and stretch your legs – and we’re still working out some of the details, but we’re aiming for a distinct identity that feels rewarding on its own rather than feeling like the player is wasting time away from the “good parts” of the game.

And not for nothing, it fits nicely with the Perfect Minute Games ethos – we make short, beautiful games for smart, busy people.

If You’ve Read This Far, Thank You!

So that’s where we’re at as far as the high notes go. I’d like to talk sometime soon about the other end of the design process – the nitty-gritty details of planning each thing in a way that will lead to a reasonably well-defined end goal – but for now I’ll leave you with this teaser for our forthcoming art devlog.

Meet the Paint By Monsters Demo Full Cast!

Left to Right: Barber Surgeon, Dandy, JuggerKnight, Giovannia aka The Artist, Blemmyae, Nucklavee, and Monopod

Featured Image

19th century engraving of The Trusty Servant, from the 1579 painting by John Hoskins (public domain).

Paint By Monsters DevLog 5 – Shader Experimentation

It’s been entirely too long since I was last able to talk about the development on Paint By Monsters, but with the Conceptualization Funding sorted and a partnership forged with the incomparable Stellar Boar Productions, I’m finally able to put a little of the old grey goo to work on matters technical and creative.

So: Shaders. This goes back to the thread that was originally pulled when I started with the Brush Stroke feature demo. There are lots of ways to paint stuff in Unity, but I’ve been meaning to take a deep dive (ok, a shallow dive) into shaders for a while now, and this seemed like a good opportunity.

If you want to jump directly to the shader itself, it’s here:
https://www.shadertoy.com/view/Dt2XWG

Otherwise, please, read on.

The Joys of Shadertoy

If you’re not already familiar with Shadertoy, it’s a website that allows you to create complex shaders within your browser, which is just the kind of nonsense that leads to a Destroy All Software talk. But it’s also just kind of awesome, since it lets you mess with shaders on a tight loop of try-fail-swear-fix-enjoy.

I looked at a bunch of different shaders, mostly having to do with mouse trails and such, but when I started iterating I took opexu’s Mouse Trails Soft shader as my jumping-off point. Obviously it doesn’t really look quite like a paint effect, but it leaves a persistent trail of colour based on mouse input, which is about as good as it gets.

I’ll admit I’ve forgotten a lot of what I learned back when I was experimenting with the Kinect. I’d half-forgotten I even wrote a post about a shader with inputs. As a result, I had to relearn some things.

Shadertoy uses a different representation for shaders than Unity, because nobody who implements a shader architecture can seem to leave well enough alone. If you’re not familiar with one or the other, I’d encourage you to read the Shadertoy and Unity documentation, but the short version is that in addition to the Image code (which determines the onscreen color of each fragment), Shadertoy allows you to use up to 4 buffers, and each buffer (plus Image) can accept up to 4 inputs (iChannel0-3).

Mouse Trails Soft uses one buffer, which is where it holds both the image so far and the last known mouse pointer position. The latter is by turns both clever and wasteful, but in this specific case it makes sense.

BufferA takes BufferA (ie itself) as input on iChannel0. It took me a while to suss out enough details to grok the relevant details here, so don’t worry if the following looks like gibberish right now.

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{   
    vec2 uv = fragCoord/iResolution.xy;
    vec2 aspect = vec2(iResolution.x/iResolution.y, 1.);
    vec2 uvQuad = uv*aspect;
    
    vec2 mP = uvQuad - iMouse.xy/iResolution.xy*aspect;
    float d = 1.-length(mP);    
    
    vec4 bufA = texture(iChannel0, uv);
    vec2 mPN = bufA.zw;
    vec2 vel = min(max(abs(mPN - mP), vec2(0.001)), vec2(0.05));
    
    d = smoothstep(0.85,1.3,d+length(vel))/0.4;
    vec2 dot = vec2(d);

    dot = max(dot, bufA.xy);    
    vec4 col = vec4(dot.x, dot.y, mP.x, mP.y);
    
    if(iFrame == 0) {
        col = vec4(.0,.0, mP.x, mP.y);
    }
    
    fragColor = vec4(col);
}

I went through this code slowly, teasing out the meaning of each line.

  1. OK, so uv is the texture coordinate normalized by resolution
  2. Aspect is the aspect ratio
  3. uvQuad is the aspect ratio-normalized coordinate
  4. Wait, but we’re adjusting by the mouse coordinate
  5. Ok, uv is the coordinate of the current fragment.
  6. So mP is a resolution+aspect-normalized vector from the mouse to the current fragment
  7. And d is initialized to…the one’s complement of that?
  8. bufA is the existing 4-component color at coordinate uv
  9. mPN is the…zw value of that value? Which is actually the x and y value from last frame?

For full clarity, the Image code is below, but it’s mostly just repeated setup. This is the point where I realized that I don’t need to understand every detail. Maybe you can tell me why that col *= uv + 1-uv is there.

void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
   vec2 uv = fragCoord/iResolution.xy;
   vec2 aspect = vec2(iResolution.x/iResolution.y, 1.);
  vec2 uvQuad = uv * aspect;
  vec4 bufA = texture(iChannel0, uv);

  vec4 col = bufA;
  col.xy *= (uv.xy+(1.-uv.xy));

  if(iFrame == 0) {
    col = vec4(.0,.0,.0,1.);
  }

  fragColor = vec4(col.xy, .0, 1.);
}

With my newfound (albeit limited) understanding in hand, it was time to start working on my own shader. I figured I’d learned enough to start from scratch, since the soft-circle shape was pretty far from where I wanted my code to end up.

First things first: 3 dimensional math!

I want to draw a box that is axis-aligned with the direction my mouse is moving in. The parallel portion of that is just the width of the box multiplied by the mouse’s velocity unit vector, which I can get by normalizing the velocity vector. Assuming, that is, that I can get the velocity vector. Which means I need not just the current mouse position – available as iMouse – but the previous position as well.

Luckily, that’s exactly what opexu’s trick is for. Since opexu stores one of the components in the third color component, however, it limits which colors are available. Not having a blue component seemed like a pretty big issue when Paint By Monsters is so heavily based on painting, so I decided to dedicate a buffer to tracking current and previous mouse coordinates.

And so, Buffer A was added. Buffer A takes itself as input and for each execution it puts the last mouse position into the R & G components, and the new position into the B & A components. On the first frame, it loads everything with position 0, which, as it turns out, can be a bad choice. More on that in a minute.

Buffer A uses the code below to update itself, reading its own previous contents from iChannel0.

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    if(iFrame == 0) {
        fragColor = vec4(0.0);
    } else {
        vec2 uv = fragCoord / iResolution.xy;
        vec2 m1 = texture(iChannel0, uv).zw;
        fragColor = vec4(m1,iMouse.xy);
    }
}

The next thing I needed was my persistent graphic. Again, opexu’s approach seems fine here – I can use a self-referencing buffer that just holds all of the fragments painted so far.

Thus Buffer B was added. Buffer B, as it turns out, is where the key goodness happens. Since I’m reading color from it, it needs to know about newly-painted fragments. Which means I need to paint into it, rather than in Image.

I’ll still need the mouse’s velocity vector, so I feed Buffer A into Buffer B’s iChannel0 input.

vec4 bufM = texture(iChannel0, uv);

I can then calculate my velocity vector.

vec2 mouse_move_vec = bufM.zw - bufM.xy;

As mentioned previously, I wanted a simple box-shaped brush for this iteration on the shader. The vector “width” of the box can be represented as w * vb, where w is a scalar equal to half the full width of the box. This, by itself, defines a narrow, infinitely tall box. We can calculate whether a particular fragment falls within the width box by projecting it onto the velocity vector.

The vector of interest, in this case, is the absolute distance – along a vector parallel to the long axis of the box – from the fragment coordinate to the centre of the box. We first need to calculate the vector between our fragment and any point already known to lie within the box – v_mouse1, for example.

v_frag = fragCoord - v_mouse1;

If we take the dot product of this vector with a unit vector that’s parallel to the short axis of the box (aka velocity_normalized) – we can determine the parallel distance from the original point to the fragment coordinate.

d_parallel = dot(v_frag, velocity_normalized);

If this distance is less than w, the fragment lies within our infinitely tall box.

We can multiply this length by velocity_normalized to get the vector representation of the parallel displacement, which will come in handy later.

v_parallel = d_parallel * velocity_normalized;

The next step is to constrain our box’s height as well. For this we need the perpendicular distance from one end of the velocity vector to our fragment. If we can get a vector that is perpendicular to velocity but still in the plane of our canvas, we’re good.

The simple way to get a vector that is perpendicular to another vector is to use the cross product, represented in GLSL as the cross() function. If you’re just getting started with vector math, this can be a stumbling block – we only have the velocity vector, right?

But the thing is, we also have a 2d plane – the canvas – and a plane can be represented by a 3-dimensional vector that is perpendicular to its surface. Fragment coordinates use x and y, which means (by convention) our 3rd dimension is z.

We can take the cross product of a unit z vector with our velocity.

vec4 v_perp = cross(velocity_normalized, vec4(0., 0., 1., 0.));

However, because we calculated v_frag and its parallel component, v_parallel, there’s another, less computationally demanding way to do this.

Frame of reference transformations are beyond the scope of this article, but in essence they tell us that for any vector v_original and any perpendicular components of that vector v_parallel and v_perpendicular, by definition those components sum to the original vector.

v_parallel + v_perpedicular = v_original

This equation, however, can be rearranged to yield the perpendicular component.

v_perpendicular = v_original - v_parallel;

In our case, we already have v_frag and v_parallel.

v_perp = v_frag - v_parallel;

With both the parallel and perpendicular components in hand, we can fully constrain our fragment with respect to our box.

//Initialize with previously painted fragment color
fragColor = texture(iChannel1, uv).xyz;

// Box is 2*20 high, 2*10 wide
if(length(v_perp) < 20 && length(v_parallel) < 10) {
  // paint it red
  fragColor = vec4(1.0, 0.0, 0.0, 0.0);
}

This shader will set fragColor to red if and only if the current fragment lies within the bounds of a box of height 40 and width 20 with its shorter axis aligned with the mouse’s direction of movement. Since we’re feeding BufferB back into itself, we initialize our fragment from the previous value of fragColor, so even after the “brush” moves on, painted fragments remain painted.


Further Reading

I looked up some stuff about simulating oil paint for real, and maybe at some point I’ll put it to use, but given it will eventually get rendered down to pixel art, maybe not.

Either way, the paper is pretty interesting. Finite Element Analysis with hybrid physical models is not something I’ve seen all that often.

I also started looking up Unity videos to try and get my head back in the shaders + Unity headspace, and I ran across this video by Code Monkey, where he does something very similar to what I’ve done above, but uses C# code and MonoBehaviours instead of shaders and trickses.


Featured Image

Kaleidoscope VI” by fdecomite is licensed under CC BY 2.0.

CMF Conceptualization Iteration 4 – Funding and Bizdev and Planning Oh My!

Turns out this post is part of a series documenting my first application to the Canada Media Fund and in particular its Conceptualization program

Post 1
Post 2
Post 3

Paint By Monsters Has Funding!

I’m pleased to announce that Paint By Monsters was accepted for the 2022 CMF Conceptualization program, and has now been approved for funding by the CMF.

I’m also pleased to say the fine folks at Stellar Boar have agreed to work with me to lend their amazing artistic talents to the game.

It’s been a long road to get here, and at times I wasn’t certain things would work out. I’ve had to reflect on my goals for Perfect Minute Games itself while trying to work this project out.

The Aforementioned Long Road

In the intervening time I lost my day job, which has been rough in a bunch of different ways. But it also invites the alluring possibility of going full-time with game development.

I haven’t come to any hard decisions there, but I have come up with a kind of vision of what I think that would look like. I also had to incorporate the company, which means I’m the President and sole shareholder of the newly-minted Perfect Minute Games Inc. In other words, meet the new gamedev: same as the old gamedev.

But I’ve also got a diagnosis to think about, and its consequences have implications for me as the President of said company and its hypothetical evolution into a much more ambitious full-time pursuit.

I’m talking to some folks about further possibilities – people I want to work with, projects I want to plan for, funding I might need to execute on such a plan – and while all of that has been interesting, it’s a whole lot of work. Given I haven’t committed to this idea, that means I’m still mostly doing Perfect Minute stuff once I’ve gotten “real stuff” (job searching, grocery-getting, snow shoveling, dog entertaining, etc) accomplished each day. So for now, it’s mostly vision.

Bizzy Devvy

One of the skillsets that actually might help with turning that vision into something more, however, is bizdev. And as it turns out, I’ve actually done enough of that at this point, via various startup projects and events and communities (Oh My!), to feel minimally competent at it. I even made some slides for your entertainment, gentle player.

Pitch Deck

A pitch deck isn’t the most comfortable exercise to do for this company, not least because company decks tend to be used to attract equity investors – folks who want a piece of not just the project but the entire business. Those folks sometimes insist on conditions that can become onerous or even dangerous to the people in the company.

But the deck was still a useful exercise. It was created primarily as a preface to a conversation with the local tech accelerator, which has incubated at least two or three other studios over the past 20 years. In that context, creating a deck forced me to look at things with fresh eyes. I had to think about where I might be able to do something new-ish, something that would give folks a reason to believe that the company is worth investing in.

All of the “opportunities” I’ve identified in the deck are operational ones, which means they’re both easy to copy and extremely difficult to get right. That’s not what anyone who’s considering investing in a business wants to hear, but then again, every investor in my neck of the woods has already laughed me out of their office as soon as I mentioned game development.

Plus, there are a few companies I would say have already gotten this operational model right – PopCap, back in their early days, but also Brace Yourself and Supergiant. Those are intimidating competitors, but they’re also incredible company. One of the nice things about creative work is that nobody is really your direct competitor.

So sure, BYG are making Phantom Brigade, which is probably the best SF game you haven’t played yet, and sure, Powered A(r)mour is, in part, an appeal to all the mech game lovers out there. But that audience is far from being inundated with more great mech games than they could ever wish for. There’s even a case to be made that these two games, were they to coexist (and I hope they do someday!) would be seen as part of a larger revival of mechs in games. That’s a dream I could hang onto.

Moreover, while the examples I’ve listed are certainly worth some attention, they’re kind of exceptional. A lot of studios – especially indies – aren’t formed with a vision of company-building. They’re built around a single project, or maybe even just a group of folks making games together.

Don’t get me wrong, those are absolutely fine ways to approach things. But if you’re in my position and you suddenly need to think about what’s required to create a sustainable business, you need to think bigger.

Building For Years, Not Games

When I reached out to the accelerator folks and to the tech and business community more generally, two important questions arose immediately:

  1. What’s your revenue model?
  2. What’s your path to $1M annual recurring revenue (ARR)?

$1M ARR is a kind of survival benchmark. If you can get to that level of revenue (without burning through millions of dollars in the process), so some folks will tell you, you’ve survived the part of the curve that kills off more than half of all startups.

It’s not quite that simple, of course – startup failure statistics vary drastically by industry, for one thing – but as big a number as it might seem, $1M ARR should just about pay for 10 people and some (limited, carefully controlled) business expenses. 10 people isn’t a huge studio, but it’s over a third the size of Supergiant or BYG, both of which I’d tend to consider successful, stable entities, and neither of which is all that much older than Perfect Minute in absolute terms.

Still, a path to $1M ARR feels…intimidating. If I look at Vampire Survivors, at its $6 price point, and considering that something like $2 of that price will go to Steam and payment processing, it would be necessary to sell TWO HUNDRED AND FIFTY THOUSAND copies to reach that target. And not just one time – that number, every year, for as long as the company operates.

Now, Vampire Survivors is a breakout hit. I’m sure poncle has long since topped the million-dollar mark. But it has spawned an endless stream of imitators, and very few of those will have the same luck. You can’t bet on hits. You have to plan as if you’re going to be really, really average. Or better yet, really incredibly median.

The thing that’s required here is Market Research. I’ve been looking for publicly available game-specific market research resources for years now, and so it’s simultaneously gratifying and vaguely irritating to only just now happen upon VGInsights’ Steam Analytics and Top Charts data, not to mention their excellent indie game price analysis.

Applying the Data

Taken together, these resources offer enough information to do some back-of-the-envelope calculations about sales figures and revenue. I threw this data into the finance section of Futurpreneur’s excellent Business Plan Writer tool and exported the data to a spreadsheet that I could point to for reference when talking about revenue projections.

PMG 3-Year Financial Projections

I’m sure someone will point out that these figures are hopelessly optimistic, that the median revenue for indie games is vanishingly small, that even planning for the median requires some big assumptions. And I won’t argue those points. This is where the rest of the vision I outlined in the pitch deck come in.

Of course, you can have all the vision in the world and it’ll do no good unless you can execute. If, for example, your business model relies on launching 4 games a year, you can’t half-ass it. But that’s what project plans are for.

3-Year Resource Allocation Plan

It’s hard to look at that plan and not think of all the ways it could go off the rails. But you don’t necessarily have to execute any plan perfectly and to the smallest detail. Nor do revenues have to track exactly with projections. Luck plays a part. The point is to give ourselves the best statistical chance we can.

Is It Realistic?

While I was working on all this, I found a bunch of gnarly issues with my plans.

Taking out a massive operating loan at 7% interest, for example, could cripple the company. The interest and principal payments could throttle cash flow long before revenue can grow enough to compensate. Better, then, to acknowledge that a smaller loan is a better option, even if it requires extra work to seek other funding options.

Ditto piling 2 years or more of non-monetized post-release work on half a dozen games on top of the effort required to actually build the next game. It’s critical to control the amount of work in flight at any given time. Putting the numbers into a spreadsheet I discovered exactly how hard this vision would be to execute successfully. But I also confirmed that it is doable, at least on paper.

Just as importantly, I believe that having a plan, however starry-eyed it may be, is a necessary first step towards success. I don’t know what the next step will be, or whether I’ll take it once I do know.

For now, though, I’ll just say:

I did this, so you can do this. Take whatever value you find in what I’ve written here. I hope it helps you figure out some important bits of your own starry-eyed vision.


Featured Image: “Construction Tunnel” by chrismetcalfTV is licensed under CC BY 2.0.

Paint By Monsters: DevLog 4 + Feature Video 0.0.10 – Brush Strokes!

I’m gonna talk about all the faffery in a minute, but if you want the TL;DR, I invite you to take a look at feature video 0.0.10 – Brush Strokes;

Why “Brush Strokes”, Cousin?

One of the folks in my local gamedev community, the incredible artist rsvpasap, asked me a while back what kind of “painting” there was in Paint By Monsters, and at the time I didn’t have any kind of sensible answer for them.

Well, now I do, at least in the first-proof-of-concept sense. The Brush Strokes feature was directly inspired by that conversation, and I hope Angie would be proud to have sent me down this road.

On Assets, Asset Markets, and General Faffery

I’ve been mostly buying assets for PBM from itch.io artists, but there’s only so much content you can find there. I’ve looked at a bunch of new spots, particularly ArtStation and the Unity Asset Store, and in the latter I happened across the Gesture Recognizer asset.

This asset, on its face, is exactly what I wanted for Brush Strokes – a clean, simple asset focused specifically on recognizing a range of gestures, with good editor integration and the ability to create new gestures without a lot of faffing about. So, you know. Good job Raphael Marques on that front.

Unfortunately, Gesture Recognizer has a few problems out of the box that make it less than ideal to work with as of this writing. Maybe the creator will update it sometime, but in the meantime let’s talk about how I approached the issues that I encountered.

Fixing Gesture Recognizer

The first problem – and really, this is as much an indictment of Unity as a vetting agent as it is of the asset creator – is that unless you’re starting with the example level included with Gesture Recognizer, creating a new Gesture and trying to fill in the ID field causes a whole boatload of exceptions to show up in the Console Log. These will lead you back to the GesturePatternEditor.OnInspectorGUI method, and in particular to this line of code:

var closedLineProp = gestures.GetArrayElementAtIndex(currentGestureIndex).FindPropertyRelative("closedLine");

There are two exceptionally unfortunate things about this line of code. The first is that nowhere does the editor code check to see whether currentGestureIndex is a valid index for the gestures array. The second is that it is only really required in a small subset of gestures, because closedLine is only a concern when you’re closing a gesture that contains a closed loop of some kind.

My solution to this issue was relatively simple. I put an if statement around the entire editor block containing this piece of code:

if (gestures.arraySize > 0)
{
    //do stuff, including the array access
}

This fixed the editor errors, at least for the cases I care about.

I ran into some issues with the OnRecognize event that the asset uses, but I can’t 100% rule out PEBKAC for those, so I’ll just state for the record that Dynamic Events are tricksy, and you should look for them at the very top of the event list for the handler object.

I don’t really want to admit how long it took me to find that entry, but…it was a long time.

The Other Problem With OnRecognize

The really tricky bit with this event, however, is that the parameter for the event, RecognitionResult, only includes the points from the recognized gesture. The asset seems to be focused on some kind of cleaned-up vector drawing use case, so I’m sure that works great in that circumstance where you’re doing the scaling and whatnot in another component (for the record, you probably need to inherit from DrawDetector to do that properly).

But if you’re more interested in the gestures themselves – place, size, all that kind of stuff, and if you want to keep things nice and centralized to boot – you’re going to want the points as measured at the time of input.

Now, I’m not proud of my solution to this one, but I will say that it serves the purpose, and that’s enough for the kind of rapid feature iteration I’m doing on PBM. What I did was this: I changed the array of points that define the input being examined – which is a member variable in the object that invokes OnRecognize (that is to say, DrawDetector) – from private to internal.

internal List<UILineRenderer> lines;

This lets me do the following in my event handler:

var cam = FindObjectOfType<Camera>();
var dd = transform.GetComponentInParent<DrawDetector>();
var lines = dd.data.lines;
var line = lines[lines.Count - 1];
var point1 = cam.ScreenToWorldPoint(line.points[0]);
var point2 = cam.ScreenToWorldPoint(line.points[line.points.Count - 1]);
Vector3 gestureVec = point2 - point1;
Vector3 gesturePos = ((point1 + point2) / 2.0f);

This works for basically any straight-ish line, and gives me the two primary things I care about:

  1. The position of the gesture in world space
  2. The orientation of the gesture in world space

I expect to have to do more complex analysis for future specializations, but these two vectors allowed me to specify

  1. Where my brush stroke effects appear
  2. How big they are
  3. What their orientation is.

Of course, then I had to figure out how particle system shapes work and how they interact with the Position, Rotation, and Scale of their host GameObject…but more on that next time.