I’m Still Here!

It’s the last day of 2018, and I thought I ought to do a quick retrospective to evaluate where I’ve been and where I’d like to go next year.

In late 2017, I’d decided to get back into game development. I’d returned to work and established myself in my new role. Once I’d caught my breath, I was hit with the itch to create again and took stock of my situation:

  1. There was just one of me, and that’s the way it would likely be (unless money was involved).
  2. If I had to go it alone, I was going to have to re-learn GML – I’d forgotten most of what I’d previously studied

I got back into the swing of things easily enough, but once again, game development took a backseat to other responsibilities.

Around June or so, I started on a spiritual successor to Porker – a Legend of Zelda-style action RPG. I’ve been working on it on and off as time permits, the majority of which has been spent building tiles and character animations.

In early August, I approached a friend and co-worker of mine to see if he had any interest in working together in game development. Being a professional developer, I figured he’d take to GML quickly seeing as how he already had a grandfathered copy of GMS.

We decided it was best to start with a simple game just to see how well we’d work together and aimed for a project that would take no more than 2 weeks.

We settled on a remake of Rhett Anderson’s Arcade Volleyball:

Arcade Volleyball for DOS gameplay animation

Weeks turned to months (about 4 so far) and what we ended up with was…well…very different :)…

It’s called Milk Smugglers – it’s about a pair of inter-dimensional travelers trying not to get caught with a contraband gallon of Grade A Goat’s Milk!

All of the assets are created – there’s a bit of programming that still needs to be done, but all of the game assets are finished (music, sound effects, artwork etc.).

So What Happened to Beaster?

The short answer is that my imagination exceeded my capabilities. I have a lot more growing to do before I’ll be able to tackle that project, and will return to it after completing Porker II and Milk Smugglers.

That said – I wish you all happy new year, and hope that 2019 brings with it some new releases!

Porker Let’s Play Campaign – Post Mortem

In the wake a half dozen or so key requests on WeaselZone.com which yielded no Let’s Play videos, I decided to do a post-mortem on my advertising campaign to evaluate what went right and what went wrong.

###

It’d been a little over a year since I programmed Porker: The Quest for Tastiness. That little game was never intended to be a serious endeavor, but rather a means to get some experience creating and publishing a game.

All of that changed on on February 12, when I’d noticed a couple of kids had:

  1. Found that obscure little game on GameJolt
  2. Installed it
  3. Played it
  4. Posted it on YouTube

They did this all on their own, without any prompting, incentive or instruction.
I was so inspired and encouraged by their Let’s Play that I decided go ahead and expand the game significantly into a fully-featured game.

It took about 2 months to finish the game, and I was very proud of the result. We started looking at ways to advertise and I’d settled on engaging the YouTube Let’s Players community. After all, that’s where it all began, right? What follows is how I went about it and what I learned from the experience in hopes that this may help another fledgling game developer…

###

The Popularity Paradox

Although I did not coin the term, “Popularity Paradox,” as far as I am aware (as evidenced by the entire 2 minutes of Google Fu I spent looking) I’m the only person who has applied to the term to this context:

…many indie games become popular because they receive a lot of YouTube coverage from Let’s Players, but Let’s Players tend to only review games that are already popular…

Therein lies the rub! While I sent keys to the usual 1M+ subscriber Let’s Players, I doubted any of them would ever see, let alone play my game. My research seemed to indicate that their backlog of Let’s Play games was dictated by their audiences, usually by popular request via Reddit or some other medium.

So instead, I focused on smaller to medium sized channels, who I hoped would be willing to do a fellow small-fry a solid. Here are the numbers…

I started with the [now defunct] YouTuber Gaming Megalist, a spreadsheet of over 5,000 YouTubers and their demographic information. As I went through the list, I was able to prequalify about 100 or so potential YouTubers, spending about 5 minutes each on their channels to answer the following questions:

  • Do they post frequently (at least once a week)?
  • Do they cover small indie games, or just the ones everyone else is playing?
  • Does their ‘about’ page encourage developers to contact them, or state that they play indie/random/rage games?
  • Do they have an email address?

If I could answer, “Yes!” to all of these questions, they received a..

  1. Personalized message, tailored specifically to them (no mass-mailing)
  2. Game key for Porker to use for a Let’s Play video
  3. Let’s Player’s guide (PDF)

Of those original 100 or so emails sent out, 25 clicked the link to view their key, and of those, 14 claimed their key. Of those, only 3 went on to make Let’s Play videos.

So how do those figures stack up? Well according to Mail Chimp’s Email Marketing Benchmarks*, the Games industry average was a 19.71% open rate, and a 3.19% click through rate.

Since I emailed my recipients by hand, one message at a time, I can’t really say how many of the 100 odd that I emailed a key to actually opened the message, so instead I’m going to consider “key views” to be my open rate and “key claims” to be my click through rate.

Using those metrics, my open rate is 21% higher than the industry average, and my click through rate is nearly 4.5x greater than what I should reasonably expect.

I suppose that a 21% conversion rate (i.e. ~ 1 out of every 5 people who claimed a key made a video). That’s not terrible, but that was result of about 80 hours of work on my part…

I don’t have a full-time PR person, and have no way of distinguishing between people who are serious about exchanging services by helping each other grow versus dishonest scammers who just want something for nothing.

Going forward, if I do hand out keys, I will use a service like distribute() to do it.

Changes

“Time may change me, but I can’t trace time.” – David Bowie

About 8 weeks ago, I celebrated my 1 year anniversary in my new role. A week after that, my manager resigned and I was tapped to take his place. Since then, it’s been a whirlwind of changes and new responsibilities.

By all accounts, this is old hat for me, but the demands on my time have increased significantly, becoming greater and greater as I unravel years of mismanagement and willful neglect.

While I’m very happy in my new position, I am busier than ever, and even less inclined to do anything productive when I get home after 10-12+ hours of skull sweat…

Pressure requires a release valve, and lately, my pressures had been relieved by playing games rather than making them. What’s worse is, these games introduced a whole-new set of pressures and demands on my time – so much so that it felt like a second job, albeit one which I wasn’t being paid to do.

###

While playing games can be fun and interesting, that part fades quickly. What keeps me interested is the social interaction; meeting and spending time with new “friends”. What I found was that for the people I was spending a great deal of time with, the opposite was true – they had no interest in camaraderie, just a person to occupy a seat at the table so they could carry on their game.

Maybe it’s the age gap speaking here, and relationships have given way to instant gratification – maybe I found myself surrounded by the “single serving friends” of Chuck Palahniuk’s Fight Club…

So what did I do? I withdrew…

 

Credits: featured image, “Butterflies” by M.C. Escher

Dreams and Doldrums

“…there is no way that writers can be tamed and rendered civilized. Or even cured. In a household with more than one person, of which one is a writer, the only solution known to science is to provide the patient with an isolation room, where he can endure the acute stages in private, and where food can be poked in to him with a stick. Because, if you disturb the patient at such times, he may break into tears or become violent. Or he may not hear you at all… and, if you shake him at this stage, he bites…” – Robert Heinlein

These days, I find myself short on energy. It’s hard to concentrate on programming when my office is in shambles and there is no shortage of housework to be done: Painting, decorating, yard work, hauling off lots of junk left – some of it mine, but the majority belonging to my former house sitters and their extended family – all of it needs to go!

Despite so much to do I find I have little time or energy to do much of anything after a long day of work… Mostly I just sit lay about and watch videos until I fall sleep.

When I sleep, I dream. My unsatiated creativity gives way to restless nights of dreams, urging me to return to my unfinished work. Somehow, distractions always seem to overtake me, and before I know it, a whole day is wasted with nothing to show for it but writers block.

In other news, my code-signing certificate has been renewed despite having a few new hoops to have to jump through.

I need to find inspiration, and I need to organize my office into something conducive for productive work.

The Fourth Level

As mentioned in a previous post, Level 4 of the GPC was not a lesson, but rather a series of challenges meant to reinforce what was taught in Level’s 2 and 3. This time, I elected to create a new game rather than modify an existing one.

I settled on a top down shooter/adventure game and added features and flourishes as I went along. I used my earlier conceived true grid movement code, but this time, I used a switch statement instead of a series of if statements (or at least fewer of them):

switch (keyboard_key)
 {
  case vk_left:
  case ord("A"):
     sprite_index=spr_player_walk_left;
     if moving=0 {
       moving=1
       instance_destroy(obj_target) 
       target=instance_create(x-64,y,obj_target)
       move_towards_point(target.x,target.y,4) 
      }
      break; 
 case vk_right:
 case ord("D"):
    sprite_index=spr_player_walk_right;
    if moving=0 {
      moving=1
      instance_destroy(obj_target) 
      target=instance_create(x+64,y,obj_target)
      move_towards_point(target.x,target.y,4) 
     } 
     break;
 case vk_up:
 case ord("W"):
    sprite_index=spr_player_walk_up;
    if moving=0 {
      moving=1
      instance_destroy(obj_target) 
      target=instance_create(x,y-64,obj_target)
      move_towards_point(target.x,target.y,4) 
    } 
    break;
 case vk_down:
 case ord("S"):
    sprite_index=spr_player_walk_down;
    if moving=0 {
      moving=1
      instance_destroy(obj_target) 
      target=instance_create(x,y+64,obj_target)
      move_towards_point(target.x,target.y,4) 
     } 
     break; 
 }

While trying to figure out line of sight, I came a new function:

collision_line(x,y,obj_player.x,obj_player.y,obj_barrier,1,0)

That was my first time using the collision_line, which I don’t think is covered at all in the GPC, though it might be included in his how-to’s somewhere…I came across it after watching a tutorial video by “GM Wolf” on YouTube:

This would have solved a lot of issues for me…for instance, in a previous project, I had an idea to create a trap comprised of two moving blocks which collided into and bounced off of each other. While everything worked fine, it would occasionally cause the block to get stuck in a wall. This happened because it’s movement caused it to overlap before it detected the collision, thereby getting stuck inside the wall, unable to go anywhere.

I solved this before using the place_meeting function, but was never introduced to the End Step Event, which  would have been the right way to do it. Nevertheless, I can think of other uses for collision_line and am glad I learned of it!

All in all, I spent about 2 days (most of the weekend) working on this little mini-game, and here are some of the features I included:

  • Destructible walls that advance in damage by manipulating the image_index
  • Enemies that can navigate mazes (using John Janeka’s code from Level 12)
  • Line of Sight for enemies with projectiles
  • Health, ammunition and keys global variables that persistent between rooms
  • Lock and key mechanism
  • A switch that reveals the exit when touched
  • Randomized muzzle flare and smoke when firing bullets
  • Randomized impact splatters when an enemy is hit
  • Different sounds for each impact
  • Randomized health power up sprites to add variety using a single object
  • Exits that allow you to advance to the next room
  • Capped health at 100%

What I not did include were:

  • Fail condition/game over when you run out of hitpoints
  • Start screen
  • Game Over screen

All in all, it’s a neat little game though unfinished, and good practice for more serious projects to come!

GPC Level 3 Revisited

Shortcuts…

With my files recovered, I’m free to concentrate on getting back to my second run through the GPC. I’m back to Level 3, and bits and pieces of the GML syntax are coming back to me.

For instance, when calculating variables, the course suggests something like this:

hitpoints = hitpoints + 1

This works of course, but he also suggests that hitpoints = +1 does not work, which is true, however, if you reverse that (e.g. hitpoints +=1), it does the same thing with fewer characters to type. A small, but useful time saver.

###

A Hamburger That Fires Bananas (Improved)

In GPC 3-03-A, he introduces a function that randomizes an integer:

irandom_range(0,100)

This allows you use a random number generator (RNG) to decide the outcome of a particular variable within a specified range (i.e. 0 to 100 in the code above). This is used to manipulate the direction that a hamburger fires bananas, and the speed at which they are fired.

I took this a step further by adding the following step event (pun very much intended) to obj_banana:

image_angle+=speed*10

This (in my most humble opinion) makes the bananas far more interesting/exciting to watch as it causes them to spin through the air at a speed consistent with their velocity – i.e. a fast traveling banana rotates faster than a slower moving banana.

Try it yourself!

Aside: I couldn’t help but giggle at the silliness of this lesson – you wouldn’t think a burger that shoots bananas would be so amusing but you’d be wrong! Very entertaining stuff 🙂

Switching Things Up

In Level 3, “Challenge 2 – Random Generation,” the student is required to write a series of if statements to randomly move the player character in one of 4 orthogonal directions.

In my first time around, I recall touching on Switch statements, which can be a good way to handle this very scenario. Here’s how that would look:

Instead of this:

num=irandom_range(1,4)

if num=1 {
direction=0
speed=4
}

if num=2 {
direction=90
speed=4
}

if num=3 {
direction=180
speed=4
}

if num=4 {
direction=270
speed=4
}

You could do something like this:

speed=4
switch (irandom_range(1,4)) { 
 case 1: direction=90; 
 break; 
 case 2: direction=0; 
 break;
 case 3: direction=270; 
 break;
 case 4: direction=180;
 break;
}

This seems like a far more efficient and cleaner way to handle multiple (more than 3+) consecutive if statements, but is cheating at this stage as Switch isn’t covered in the GPC until much, much later*…

So why mention it now? Because I want to get in the habit of making my code clean and efficient.

And with that, on to Level 4!


*I can’t quite recall exactly when this was introduced… For all I know, it may not have even been in the GPC, but if I do come across it later, I will update this post with where you can find it.

Transition

“Use a superior development system than your target to develop your game.” – John Romero, Early Id Software Programming Principles

One of the nice things about being employed again was the ability to afford a new computer, something I’ve put off as long as I could.

About 5 years ago, I’d purchased a very high-end mobile workstation to take with me overseas so I’d have something to keep myself entertained on the 26+ hour flights to and from the US:

  • Intel Core i7 3630QM @3.2GHz
  • 32GB of DDR3 RAM @ 1600MHz
  • Nvidia GTX 675MX 4GB of VRAM
  • 120GB SSD Primary Drive
  • 1TB Storage Drive

When I came back home, I found it more convenient to develop on my aging desktop machine with ideas of upgrading it when possible:

  • Intel Core i7 2600K @ 3.4GHz
  • 8GB DDR3 @ 1600MHz
  • AMD HD 5770s 2GB VRAM (x2 in Crossfire)
  • 120 GB SSD Primary Drive
  • 80GB SSD Auxiliary Drive
  • 320GB Storage Drive
  • 1 TB Secondary Storage Drive

A couple of months ago, I built myself a new PC that should last me a good 3-4+ years with minor upgrades:

  • Intel Core i7 7700K @ 4.2 GHz
  • 16GB DDR4 @ 3000MHz
  • Nvidia GTX 1080 8GB of VRAM
  • 240GB SSD Primary Drive
  • 2TB Storage Drive

I’ve been very pleased with it so far, and have been slowly reinstalling my development tools. The next step was to copy down my data so that I could pick up where I left off. To facility this, I purchased an inexpensive but well-made USB 3.0 SATA Hard Drive Docking Station.


What was intended to be a simple task, however, turned out to be anything but…The data I needed was spread across 4 different drives, one of which was BitLocker encrypted. The machine itself belonged to me originally, was lent a friend who in-turn savaged it, replacing several of the drives and the OS. On the actual computer, I’d solved this using Windows Libraries, but didn’t have that luxury when reading the raw drives.

So what did I do? I incorporated a handy application called SpaceSniffer to help me work out [visually] where the files I was looking for were.

This application is very similar to WinDirStat, but performs significantly faster. I still have a few more applications to [re]install, but I can get that done tomorrow at some point as it is now 4:13am, and I should think about getting to bed as I have to be up in 3 hours.

Here I Go Again on My Own

It’s been over 6 months since my last post. I’ve settled into my new role, and as the year winds to a close, I’ve been getting the itch to return to game making. Unfortunately, circumstances are such that I’ll be going it alone as Eric has retired from V-Toad Games.

Game programming and design is difficult, frustrating, greatly rewarding -but it’s not for everyone. What I learned from my last go at it was that programming is not painting by the numbers. Being able to complete an exercise no more makes you a programmer than following a recipe makes you a cordon bleu chef. There are core skills you have to master, and to do that, you have to be passionate enough to stick with it.

Eric really tried – I sincerely believe that. Nevertheless, I know all too well that bills must be paid, and can’t blame him for not having the energy to go home and learn something that he just wasn’t passionate about.

So why is being a solo project a problem for me? Many game developers, past and present, were/are one-man shows. I suppose it’s because I like feedback; I like to share what I’ve learned and bounce ideas off of other people because this helps me to reinforce and retain that knowledge.

As a consequence of my hiatus, I’ve all but lost everything I learned about GML, and will need to go through the lessons again to get back in the saddle. This time around should be much quicker, albeit lonelier.

“…Here I go again on my own…” – David Coverdale, Whitesnake

Keeping the Lights On

A couple of weeks ago, I found a new job through a good friend of mine. It’s a technical role, pretty much what I was looking for…The pay could be better, but it’s good enough for now.

They have a lot of challenges, but none are particularly difficult to resolve. It’s just going to take time and money, and the business has to decide to move forward.

Needless to say, I’ve got about 2-3 months worth of 60+ hour weeks ahead of my friend and me to right the course. Once things are stable enough to be able to work only 40 hours a week, I can return to game development. Until then, I’ll just have to pick at it when time and energy permit…

Get on with it!!!

Conflicting Priorities

I spent most of last week preparing for a face-to-face interview, pouring over the job description and reviewing every detail so as to be prepared for whatever the interviewer might bring up – this meant putting just about everything else on hold and using every waking moment to study.

The interviewers seemed pleased with me, and I was disappointed to learn that the job descriptions were erroneous; most of what were listed as, “required skills” weren’t required at all! What a waste…

Earlier this week, I received a call back from the recruiter explaining that they elected to go with someone else. In short, a week wasted and nothing to show for it but a heaping helping of disappointment…

###

After about a day of laying about and feeling sorry for myself, I decided that what I really needed was to focus on something productive… the game I’d set aside to study up for the interview was sitting there, 90% done, waiting for me to cross the last mile…

“If you know where you’re going, you can get there very fast.” – Grandmaster Henrik Danielsen

The most time consuming part of making any game is getting a clear picture of what you want to do. This is true for every component, whether it’s creating artwork, making sound effects, writing music or programming.

Of these, artwork is probably the most difficult (for me) and time consuming…  Often times, I may not have a clear mental picture of what I want to do, and haven’t developed a good system for working through ambiguity yet – but once I do break through, things move very quickly!

I’ve accomplished more in two days than I have in the last 2 months, and the end is in sight! All that’s left is just putting in the time I need to spend to get through the last few pieces, a few days more to test, then on to distribution!

With luck, I’ll have a successful YouTube marketing campaign and will sell enough copies to support myself until I finish Beaster’s Dungeon.