Tag: Game Maker

“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

“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.

AI_targeting debrief

First, who would have thought that one small component of AI behavior for my game would have taken so long to get working?

I was on a good roll, making steady progress on my project for most of December. Then the holidays hit and I couldn’t work on the project as much as I wanted. I had also just started to run into some stuff that was a little tricky (not that it was really hard, just that it was new to me) around this time, so the lack of putting time into it also made me feel nervous that I’d get stuck. There’s no way I’m ever giving up this project until I complete it, and that’s that, but I’ve run into problems in the past with projects where I get stuck, don’t know where to turn, and it sucks a lot. Oftentimes that puts the entire project at risk. But this is a project that I’ll never accept failure on — I’m working on an idea I had 30 years ago, and if it’s been in my head that long, and not gone away, it never will.

So, into January, I had less time than I hoped to get back into the project. When I did, I wanted to make the time productive, so I tended to pick things that I knew I could do, and that needed doing, but not necessarily the thing I’d gotten stuck on. That’s OK, but normally when you see something is going to be hard for you to figure out, you should wade into it and tackle the problem. I didn’t do this with myself, so much as I tried an idea a little bit, and when it didn’t do what I was expecting, I put it aside again and worked on something where I had more traction. I had a fatalistic sense of “When I am ready for this to make sense to me, it will.”

Also, during a lot of this time I was spending a lot of my project time on reading documentation, not coding. It was a struggle to make sense of what I was reading. My mind kept tripping up on something that didn’t make sense to me, and which in the end turned out to be inaccurate (unless I *still* misunderstand something, but I don’t think so). So that wasn’t too helpful.

In the reading that I did, I discovered a lot of things that merited further reading, and had to trace down a lot of avenues that potentially could have led to my solution, but didn’t. This wasn’t wasted time, though, because a lot of that stuff may end up becoming useful later, and having a clue that it’s out there is going to be helpful down the road.

Ultimately, I was able to prevail over my problem, get un-stuck, and deliver a working proof of concept. I need to do some further work to turn this proof of concept into an extension that I can import into any future Game Maker project that I work on, and from there I still need to bring it into my game project. But that’s all academic, and I have no doubt that I will get it done, and so I’m able to confidently declare victory at this point.

My initial attempts to implement the solution I was after focused on doing it directly in the current game project. I’ll call that a mistake now. For one, the existing game already has a lot of stuff in it, and the complexity of it makes it difficult to see (or think about) any new problems clearly. I had several false starts which ended up failing, trying this way.

Eventually, I got to the point where I recognized that what I needed to be able to solve the problem was simplicity. So to get that, I started a new project, and threw into it just enough bare bones to provide me with the building blocks I needed to test out the AI code that I was trying to figure out how to write.

So I did that. Twice. The first time was almost right, the second time was right, at least so far as it went, and I’d figured out enough to know that what I’d built there would work for what I need, but I need to do the rest of it back in the main project. The first attempt help me to figure out what I was doing wrong, or rather, what I needed to do.

So, that exercise was very beneficial. The second attempt only took me about 5-6 hours of hacking away at it to get it to work, which is about par for every other feature that I’ve committed in the project so far. So the fact that it took a few weeks of thinking, procrastinating, reading, and trying various things doesn’t worry me so much. I know the next time I get stuck with a problem like this, I’ll get to the solution that much sooner because I can take this general approach to it.

What was the most useful for me in solving this was the stuff I built into the project to provide me with feedback so I had something to diagnose. I strongly recommend building instrumentation and logging capabilities into whatever code you write. Otherwise, you’re only able to see what you can observe from the outside, which often ain’t much, and is apt to be very confusing when the application is behaving in some bizarre, unexpected way that you can’t figure out based on what you thought your instructions were saying to the compiler or interpreter.

2D Targeting for AI in Game Maker 8

After several weeks of effort, I have finally nailed an effective set of 2D targeting scripts for AI in Game Maker 8.

The story for this is worth telling sometime, but for now I’ll just be posting a video demo:

Source .gmk is available on Releases.

I’ll be refactoring this into a Game Maker Extension (.gex) soon as well, which will also be available along with full source.

4 quick GML coding tips

When writing scripts in Game Maker Language projects, I have come to realize a couple things that I want to share for anyone else who might be working on GML projects:

GML parsing is a bit loose. This makes the language fault tolerant, which is nice for newbie programmers who don’t need to get beaten up for not following strict syntax. But by enabling you to get away with imprecise syntax, it lets you get in to trouble that isn’t easy to detect.

Strict syntax is your friend, if you have it as an option in the language you’re using, I recommend following it as soon as you’re comfortable. Strive to get comfortable as quickly as possible. Unfortunately, GML does not have a strict mode…so I have the following tips to offer:

  1. Scripts (sometimes referred to as “programs” in the official Game Maker documentation) are supposed to begin and end with curly braces. The interpreter is forgiving if you don’t do this. But you should always do it.
  2. GML terminates statements with a semi-colon. The semi-colon is semi-optional, but I recommend using them wherever you intend a line of code to end, so that the interpreter doesn’t have to do extra work guessing that for you. Doing so will make it look like you know Pascal, C, or Java more than you know VB, which is enough reason to do it;) (Usually a statement is more or less the same thing as a line of code in your script file, but some structures may incorporate blocks of code, such as loops or branches.)
  3. Strings in GML can include line break characters (there’s no escaping with \n or using a character code like CRLF, like there is in most languages), so if you want to have a string with a line break in it, you simply hit the enter key and put a literal line break in your string. The interpreter handles this OK since the string is bounded by double or single quotes, but it’s still a weird thing about the language that they don’t really explain adequately in the documentation. If you’re not using semi-colons where you intend to end a line, it can get confusing to look at a multi-line string declaration that incorporates the line break as part of the string.
  4. It’s easy to not scope your variables appropriately without realizing it. GML allows global vars, and has two kinds of locality: locality with respect to an instance of an object, and locality with respect to a script. You shouldn’t use globals unless you really need to; according to the language doc they are slower to access than local variables. I haven’t noticed any difference that I can measure, but I’m sure that it is something that adds up, and at any rate proper scoping is a good habit to get into.When I refactored my project to pull drag-n-drop code out and replace it with scripts that were more re-usable, this caused some of my instance variables to turn into script variables. I had to go back and turn them into instance variables once I discovered that this had happened, and caused some issues with the way the code was executed by the interpreter.If you’re using variables in a script that were not declared in the object somewhere (normally the best place for this is in the object’s create() event), and you are declaring the variable in the script, but you want to make it an instance-local variable, you can do so. The code to do this is:

    obj_MyObject.MyLocalInstanceVar

    That dot between obj_MyObject and MyLocalInstanceVar is actually an operator. Knowing this is nifty, but I am not prepared to expound on why just yet.

Keep reading the language specification doc! Every time I go back to it and read, I pick up something I didn’t know, or refine something I thought I knew. One of the really nice things about GML is that it’s a small enough language that you can pick it up and do things with the basic features right away, without needing or being overwhelmed by all the other stuff that you’ll discover as you continue to progress as a developer. And there are enough built-in features in GML that you don’t have to spend a lot of time figuring out how to build sophisticated stuff out of primitives all by yourself.

The more I work in GML, the more respect and appreciation I gain for it. It is not the purest language, nor is it the most powerful, nor is the development environment as rich and sophisticated as a “serious” IDE like Visual Studio or Eclipse, but it is extremely accessible for a non-programmer to pick up and start working with and being effective quickly.

Yummy GameMaker Goodness…

Good technical documentation is a beautiful, beautiful thing. Almost as good as bug-free code.

Ultimate DdD to GML Converter

It occurred to me recently that my Actions could be easier to understand and debug if I refactored to convert as much of it from Drag-and-Drop actions into GML scripts. It’s a LOT easier to understand a script call to “Player_Eats_Fish” than it is to read a dozen or more DnD actions that do “Player Eats Fish” and figure out what they’re doing. Plus, you can call the scripts elsewhere if you need to.

So I started doing this, and realized that there were certain things that I didn’t know how to do. Reading the language reference in the GameMaker Help helped, but at times I still got confused… Then I googled and found this. UDnD2GML does a nice job of converting Drag and Drop actions into valid and correct GML. It’s actually written in GameMaker, too; that’s right, it’s a GameMaker project that converts GameMaker drag-n-drop actions into GML. Very slick! When you need to work out a bit of tricky syntax, or are dealing with some function you don’t use a whole lot, it’s indespensible.

Drag and Drop Icons and Their GML Equivalents for Version 7.0

Basically the same thing, only a big hypertext reference document. I liked it so much, I printed it to PDF format and am keeping it with my other GameMaker docs. Although this is for GML7, there doesn’t seem to be a whole lot that has changed in GML8. Could be a bit clearer in places, and incomplete in some regards (I had to use UDND2GML to figure out how to apply instance_destroy() to other; this document was silent on that point.)

Official GameMaker 8 Help File as a PDF

Not hard to find by any means, but if you don’t have it, it’s the best place to start. A lot nicer than searching through the Help Menu index.

Boobie Teeth 0.17, CBNA SmartLight, and Google Translation

I’ve spent the last few days getting back into the Boobie Teeth project, trying to figure out how to do a couple things that have had me stuck for longer than I’d care to admit. I’m far from giving up, but I have come to the conclusion that hacking away at the problem isn’t going to be as fruitful as reading up on the problem.

At any rate, here’s a video of what I managed to pack in to today’s release, 0.17:

The major accomplishment for this release was the addition of a transparent gradient in the foreground, which enhances the background gradient that gives the illusion of diminishing sunlight at depth. For now this is just a cosmetic feature, although I already have ideas for tying it into the gameplay.

The other thing I worked with in this release, but dropped for now, is to implement some basic AI. I want the fish to get hungry and start chasing down prey. This is a lot harder than I thought it would be, owing to limitations of GameMaker’s instance handling. My usual approach of coding a little bit and seeing what I get, then coding a bit more once I’m sure what I already have done is working hasn’t gotten me very far. I’ll be researching and studying until I figure out an approach that works.

While researching, I came across a beautiful video of some lighting effects done in GameMaker which blow my simple foreground gradient away completely:

I noticed of course that the video appeared to come from French-speaking authors, but that didn’t dissuade me from tracking down the package that enables these effects and downloading it.

Let me just take a moment to say that I am absolutely amazed by the quality of google’s translation service from French to English. Seriously, click this link and you’d hardly even know that you’re on a French site. This impresses me even more than the lighting effects. If you happen to spot a mistake in translation you can hover over text and see the original, and provide feedback to google directly through the site that they’re translating for you. The translation is extremely fast, almost real-time, too.

It’s going to take me some time to work my way through the examples and tutorials and translating the documentation, but if I can get this SmartLight to work with my game project, it’s going to be well worth it, and make the game look way better than I had originally planned. I really want to get some AI going in my game though, so it’ll probably be a while before I get into re-doing the lighting effects.