“How I (FINALLY) Made My First Video Game” Notacon 8

The talk went very well. Several people I didn’t know came up to me afterward and said that it was inspiring, which means a lot to me. I tend to discount compliments from friends, which perhaps I shouldn’t, but I always throw out data that might be subject to bias.

I am posting my presentation slides here, for anyone who would like to download and read my notes. The talk was videotaped (do camcorders still use tape? No, I think we need a new word), and will be available on the Notacon.org archive once they have time to process everything. I’ll post a link when they do; might be a few weeks or months.

How I (FINALLY) Made My First Video Game – Notcon 8 2011-04-15

Edit: The videos that were embedded in the original powerpoint appear in this version of it as single frame placeholders. For the actual videos, I have them up on YouTube:

Development Stages

Builds 0.20 – 0.22 montage

Boobie Teeth 0.22

Boobie Teeth 0.22 is now available for download at the Releases page.

I figured out how to fix the bugs with the Feeder Fish, so they’re back in the game. The problem was rather complicated, and had to do with both Game Maker’s inheritance model AND the weird way that Game Maker can change an instance of one type of object into an object of another type. When Feeder Fish feed on each other, they eventually grow large enough to change into Fish. For reasons I still don’t understand, when the built-in function instance_change() is called, it results in a weird condition with the instance’s variables no longer being accessible to the application.

In my AI targeting code, this could cause a changed instance to no longer exist insofar as the Game Maker engine was concerned, resulting in an unhandled “unknown variable” exception being thrown. To work around the problem, I had to write my own code to handle the instance_change, and so it creates a new Fish, assigns it properties equivalent to the former Feeder Fish instance that it used to be, and then destroys the original Feeder Fish.

Further complicating matters was the fact that I had initialization happening in the Create event for the Fish object, which normally gives a new fish random values for its properties. In this case, however, the Create event initialization was blowing out the Feeder Fish’s properties which I’d just assigned to the new Fish. So to fix that problem, I had to remove the call to my initialization function from the Fish object, and am now calling it from outside after the Fish instance is created. The Fish Factory uses randomized values, while a matured Feeder Fish passes its original values. This works nicely, and I am happy with the result. The game is more fun with Feeder Fish acting as an attractive food source to the full-grown AI fish in the game, so I’m glad I was able to get this in before the demo at Notacon.

I also added a function to prevent fish from getting stuck on the bottom of the sea. Now if a fish swims and hits bottom, it changes course. I have seen on occasion a fish being spawned too close to the bottom and getting stuck, and will have to fix that in a different manner. I have been trying to work some safety checks into my level_spawn function to prevent the player from being unfairly killed and prevent fish from being spawned stuck in the sea floor. So far, though, this has proved tricky. I can’t simply check for collisions, because the fish’s sprite gets scaled up immediately after it is spawned, and in the first tick of the game when the fish is newly spawned, its sprite is still normal size, so an anti-collision check could still leave it too close when it spawns. As well, I can’t merely check for collisions with the Player, because I want to ensure that the Player has enough room to swim away from a nearby threatening fish. I had some experimental code that should calculate a safe clearance distance around the player and pick coordinates outside of this safe zone to place newly-spawned fish, but when I tried running it, an odd bug arose wherein the fish count function stopped working properly — I’m guessing fish end up outside the room where they can’t be seen or eaten, but I can’t see how that’s possible given how I wrote the code that checks for this. At any rate, level transitions will be a future development goal that I will work out in more detail anyway.

The game demo level is already pretty fun to play, so if you have not yet tried the game out, now is a great time to get acquainted.

Boobie Teeth 0.21

Boobie Teeth 0.21 is now up on Releases. This is most likely the last update that I will be releasing before the talk I’m giving at Notacon 8, so if you’re reading this consider it an advance preview of what you’ll see if you happen to be attending.

This release has numerous improvements over 0.20. I went through most of the script code that I wrote and reformatted it, and in some cases did some refactoring. As a player you won’t notice this of course, but it will enable me to work faster and release more frequently as I continue developing the game. I greatly simplified the collision detection, which has yielded some modest performance improvements. As a result of some of the changes I made, I had to temporarily remove Feeder Fish from the game, but I’ll be bringing them back in as soon as I can rework them properly.

Since playtesting this version, I am really moved by some of the emergent behaviors that I’ve observed. Granted, sometimes the fish do stupid things like ram themselves into the ground or continue chasing a fish they targeted that has since grown too large for them to eat. But I’ve also seen fish leaping out of the water, feeding behavior that almost looks like schooling (though it isn’t). The thing I like the most, though is a change I made to the fish’s “normal” movement behavior. Instead of moving at a fixed speed, it changes through a range of speeds every few ticks. This gives it a movement that is more characteristic of fish swimming, with a pulsating faster/slower speed to it. I find it emotionally compelling when I see a fish moving like this while being chased closely by another fish right behind it — it looks like the fish is struggling to swim as fast as it can, falling behind, going faster… sometimes they get away, sometimes the chase fish is too fast for them.

I have a lot more planned for the AI in the game, but for now it’s at a point where it is basically playable and you can get a decent feel for what the game is meant to play like. This is much improved over earlier builds where “dumb” fish simply moved horizontally at a fixed speed.

Three eras of searching the world wide web

A little late to the game and perhaps obvious, I know, but I was just musing and it occurred to me that there are perhaps three distinct eras for the way people using the world wide web have found information:

The Yahoo era: A cadre of net geeks personally indexed and recommended stuff for everyone to look at when you told them what you were looking for.
The Google era: A massive cluster of robots scoured the internet and figured out what web sites looked like they were pretty good and matched them up with what you told them you were looking for.
The Facebook era: Your friends find something cool/funny/useful/outrageous and post something about it, leading you to do the same.

Ok, so yes, that’s pretty obvious to anyone who’s been on the web and paying attention from 1994-onward or earlier. Predicting what the next era will be is of course the billion dollar question.

The obvious thing that comes to mind is that things will just remain this way forever, and of course this is false and just a failure of imagination.

The next most obvious guess at what the future will bring is to combine the stuff that happened in the previous eras in some novel way. The Facebook era is kindof like that — instead of a hand-picked WWW index managed by the geeks at Yahoo!, we have a feed (rather than an index) of links which our our social contacts (rather than a bunch of strangers working for Yahoo!) provide for us to check out.

So, perhaps just doing a mashup of the Facebook and Google eras would point to what the next breakthrough in search might look like. Let’s try that:

Mash1: Our social contacts create a cluster of robots who index the WWW and come up with a custom-tailored PageRank algorithm tied to what turns our crank.

Hmm, intriguing, but unlikely. Most of our social contacts probably don’t know enough about technology to do that.

Mash 2: The behavior of our social contacts is monitored by robots who analyze the information that can be datamined out of all that activity, and use it to beat our friends to the punch. Especially for marketing purposes.

Much more likely! What we’re doing on social networking sites is already closely watched and analyzed by hordes of robots. All it would take is for someone to come up with the idea and implement it.

And it’s a good enough idea that I bet there are already people working on this right now. In fact, there definitely are if you consider social media advertisers. But I’m also thinking about more general purpose informational search.

In fact, after I congratulate myself on what a clever prognosticator I am and hit Publish, I bet within 15 minutes someone will post a comment with a link to a company that’s doing exactly this.

I mean, of course I could save myself the embarrassment and google around and see if I could find that myself, but it’s so last-era.

I want to see whether the Facebook era will bring the information to me with less effort expended. It may or may not be faster than the google era, but faster isn’t always the most important thing — sometimes there’s a tremendous amount of value in getting information from a friend that could easily have been looked up through a simple query to google.

5… 4… 3… 2…

Boobie Teeth 0.20

Finally got hungry AI target and seek behavior working properly. Fish now get hungry and chase each other.

Download it from Releases.

Boobie Teeth 0.19

Boobie Teeth 0.19 is now up on Releases. I’ve skipped public release of 0.18, which had some experimental AI in it that proved buggy. 0.19 is mostly a cleanup release, where most of the script code has been re-written and documented better. There are a lot of new things in 0.19, as well:

  • Disabled unstable AI routines from 0.18.
  • Fixed Pause function to display “Game Paused” in center of main view when game is paused.
  • Fixed collision mask on fish sprites to prevent “close-call” collisions.
  • Major code refactor to replace drag/drop actions with GML code scripts for improved readability, reuse. This cleanup should make implementation of future features easier.
  • Menu and configuration screens partly implemented.
  • Game runs in Full Screen mode, automatically sized to the display.
  • Renamed constant “SURFACE” to SEA_LEVEL to avoid potential confusion with drawing “surfaces”.
  • Game reads settings from .ini file on load, checks values for validity, and rewrites default values to correct a corrupted file.
  • Game reads local stats from .ini file on load, updates file after each game.
  • Fixed a latent bug with the Fish-Fish Collision that resulted in fish sometimes mutually eating each other.

“Cannibalistic” AI Targeting for Game Maker 8

I’ve made an improved version of my 2D AI Targeting demo for Game Maker. My original AI Targeting was limited by the fact that an object could not target other instances of the same object type — doing so in effect would cause the seeker object to attempt to target itself.

The original AI Targeting routine used instance_nearest(), which works great if you are targeting an object of a different type. If you need to target the same type of object, however, instance_nearest() won’t help you, since the nearest instance of the same object is always self.

Using instance_nearest_extended by Kyle_Solo, I was able to come up with a routine that allows for “cannibal” AI targeting — that is, targeting an object of the same type as the seeker.

I struggled for a long time to use the instance_xth_nearest() method to accomplish cannibal targeting, which seemed to be suitable as it has a built-in criteria test, but was unable to get the function to work as desired. I’m still not entirely sure why, but I am guessing that it may be due to the “other” keyword being undefined or referencing “noone” when an object is not involved in a collision.

I ended up successfully completing the project using instance_nth_nearest and a bit of extra code which performed the criteria testing that I required. In order to get my testing code to work, I had to introduce a global variable to count the number of instances of the targeted object, so I could construct a loop to iterate over them using instance_xth_nearest(). I’m wondering if there isn’t a faster or more graceful way to accomplish this, but it works well for now.

In the video above, the Arrows target the nearest Arrow that is small enough for them to “beat”. The rule I am using here is that a bigger arrow must be 1.3x the size of a smaller arrow in order to be able to “beat” it, but this could be modified to some other condition by changing the can_beat() function. If a candidate target cannot be “beaten” the arrow considers the next nearest arrow, and so on, until all of the instances of the targeted object type have been checked. If no arrow is small enough to be “beaten”, the arrow flies in a straight direction.

Source .gml and a demo .gmk project is available at the Releases page; a .gex extension build will be released in the near future.

AutoFullScreen 1.1

After releasing my AutoFullScreen 1.0 extension for Game Maker, I noticed a minor bug with the way small rooms were being scaled up to fill the window.

When scaling up a small room, in 1.0 the scale factor is calculated by determining whether the room was taller or wider, and used whichever was the longer dimension along with the display’s corresponding dimension to calculate the scale ratio. This was close to correct, but not quite right.

In 1.1, the scale factor is calculated both ways, using the height and the width, and then use the smaller of the two room:display ratios rather than the larger of the two room dimensions. The difference is subtle, but the upshot of this is that if you try to scale up a 4:3 room on a 16:10 display using the 1.0 method, it fills the screen completely, distorting the dimensions of the room. In 1.1 the room does not get distorted, as intended.

I have fixed the bug and added a feature to the function to make the zoom function optional. If you prefer to have the room drawn at actual size, you now have that option.

The new version is up on Releases.

AutoFullScreen extension for Game Maker

I’ve now built a Game Maker Extension (.gex) version of my handy AutoFullScreen function. It is available for download on the Releases page.

The extension includes only AutoFullScreen, the version which I called AutoFullScreen2 in the .gmk that I initially released a few weeks ago. I’ll be releasing a separate .gex of the MiniMap functions eventually.

Note: To get the AutoFullScreen.gex to install into Game Maker, you must launch Game Maker using Run As Administrator.

AutoFullScreen and MiniMap scripts for Game Maker 8

I came up with some handy scripts for Game Maker 8 projects.

  • AutoFullScreen(Border_W,Border_H,objFollow):  This script automatically sets the game window to full screen mode, and sizes View0 to the pixel dimensions of the display. If the room is not as large as the display, the room is scaled up to fit the display, and will stretch to fill the display in both the horizontal and vertical dimension, which can result in distort the room if it has a different height:width ratio than the display.
  • AutoFullScreen2(Border_W,Border_H,objFollow):  This script automatically sets the game window to full screen mode, and sizes View0 to the pixel dimensions of the display. If the room is not as large as the display, the room is scaled up to fit the display, but does not get distorted by a different height:width ratio.
  • MiniMap(minimap_width,minimap_height,top,left): Sets up View1 as a minimap view of the room. Takes parameters which set the height and width size of the minimap in pixels, and whether the minimap appears in the top/bottom or left/right corner of the window.
  • MiniMap2(scale_factor,top,left):  Like MiniMap, but with a slightly different argument for sizing the minimap. Instead of sizing the height and width using absolute pixel dimensions, you provide a scaling value. The map will be sized to a proportion of the display size divided by the scale factor (e.g., a scale factor of 8 means you’ll get a minimap that is 1/8 the size of the main window.)

The .gmk file is pretty well documented, contains example rooms with reference implementations of the scripts, and can be downloaded from releases.