Saturday, March 29, 2014

Difficult to Convey...

Until I've a firm idea of how I need the cameras to behave, this week I turned my attention to another idea for Citadel which I'd jotted down in my big book of ideas many moons ago: conveyor belts.

I'd always loved the idea of the player entering a vast, underground robot factory (those robots emerging from the traps have to be made somewhere, right?), and it seemed logical that such a factory would feature conveyors (and other dangerous machinery - but more of that another time).

However, although I was keen to try out some ideas, it was tinged with the realization that I'd have to revisit the player control routines and bash them into better shape before I could implement the conveyor logic.

One of the key issues was that the player movement code used a system that counted how many pixels the player moved, in order to get the Monitor craft to stop after it had moved one tile. Thankfully, Game Maker allows you to check this with the place_snapped command (as I discovered when implementing basic enemy movement a couple of weeks ago), so my player movement code needed a revamp.

* * *

Once the basic control routines had been tweaked (which, surprisingly, worked first time after I'd fired up the code), next came the task of detecting conveyor tiles and moving the player accordingly. This is the difficult part for me - breaking the problem down through analysis and working out the best solution; sometimes there are multiple solutions, so it's always a big dilemma.

I wanted to use the typical platform game convention that a) when at rest, the player will move at the speed of the conveyor, b) the player will move slower than usual if they try to travel against the direction of the conveyor, and c) the player will move faster than normal if they move with the conveyor.

Essentially, the basic logic works as follows:

  1. Check that the player is snapped to the grid (i.e. not already moving).
  2. Check for a conveyor tile beneath Monitor.
  3. Check to see if the player is trying to move; if so, check direction and adjust speed.
  4. Otherwise, set the player's speed to that of the conveyor.

Rather than duplicate masses of code, I came up with a nifty script-based system that allows me to feed a bunch of speed parameters to a central control routine, and in practice, it worked beautifully (I actually surprised myself with how simple it was and how well it worked!).

Flushed with that success, I redesigned part of my test level to include some conveyors, and it was really neat to see Monitor riding the conveyor belts around the level!

* * *

Later on, I showed my progress to the Mrs. and (typically!) a bug chose that precise moment to appear: essentially, because the tilesize is a power of two, the player's speed must also be similarly proportioned or the movement routine messes up when the player moves too far and 'skips over' a tile boundary.

On the plus side, I did hit upon the idea of a variation to the conveyor belts in the form of a Portal 2-style Excursion Funnel (which restricts all player movement), or possibly an electromagnetic conveyor that doesn't allow the player to sidestep off the conveyor at any point. And as I was typing up this blog entry, I also hit on the idea of special switches that reverse a conveyor's direction. Hmmm!

Monday, March 24, 2014

Camera Shenanigans

I spent a little time over the weekend putting together a list of some areas of the game I'd like to tinker with; although I currently have a lot of prototyped code in the game (and nothing actually 100% finished), I'm liking the experimental phase as it allows me to a) learn Game Maker in a much more hands-on fashion, and b) helps me iron out those unexpected kinks and foibles.

One such foible reared its head over the weekend, in the form of some nasty gaps between the background tiles. I'd implemented a camera system which not only dampens the camera's movement as it tracks the player, but also allows the camera to zoom in and out (in the version of Citadel in my head, I've always loved the idea of zooming in tight in times of close combat, or zooming out to emphasize the size and scale of the underground cities).

After a little detective work - and more than a little cursing - I stumbled across this article which explains the issue and why it happens (and not a moment too soon - I'd already downloaded Unity as a threat to Game Maker if it didn't start to behave itself!). I spent an hour this afternoon tweaking the tileset, adding a gap between the tiles and padding the edges of each tile image.

After reconstructing the map, I fired up the game and the gaps had become a thing of the past - one of those classic situations where, despite the work that went on behind the scenes, the game looks virtually identical to the way it did before.

Friday, March 21, 2014

Sprite Sheets to the Wind...

The past few days have seen me dipping into other projects (i.e. paid work!), so my time on Citadel has been somewhat limited. However, I managed to use my time wisely, and dedicated my efforts to tweaking some of the graphics (now that my tile size is definitely 64x64... definitely... for now...).

One of the tasks on my list was to arrange all of the C64 sprites on a master sprite sheet, on a 64x64 pixel grid.This serves two purposes:

1. Although I import my sprites using strips, on a case-by-case basis, having all of the sprites laid out on one sheet in PhotoShop is extremely useful (not least because it allows me to see typically how much space the sprites use, and how much of each texture page remains). Plus, it means that I'm only ever updating one file - a huge pet peeve of mine is having a lot of clutter in my working folders.

2.  Currently, sprites can be any size, which can cause issues given that a) everything moves on a tile-by-tile basis, and b) things can move at different speeds. Plus, if I want a sprite to appear in the center of a tile, I have to add additional code to calculate the sprite's width and height, divide by two, and add this to the sprite's co-ordinates. Messy, and unnecessary. By ensuring that all sprites are 64x64, all sprites can have their origin set to the top-left of the sprite and everything will work perfectly.

The downside, of course, is that smaller sprites will contain a certain amount of empty space around the outer edges, but the wasted memory, at this point in time, is minimal.

* * *

In the process of laying out the sprite sheet, I needed to flip back and forth from the C64 version to ensure that my sprites were sitting in the right spot inside each 64x64 tile. Basically, C64 sprites are 24x21 pixels in size. In Citadel, everything is based around 32x32 pixel background tiles, and thus, the sprites are positioned roughly at the center of each 32x32 tile (4 pixels in from the left, and 7 pixels from the top, in case you were really desperate to know!).

On a couple of occasions, I had to do a little bit of detective work to understand why some of my ripped sprites didn't look the same as they do on the C64 (and in the process, I discovered that Martin Walker is doing an awful lot of neat stuff behind the scenes that the player will never know about or truly appreciate).

One of these tricks involves plotting a different background tile behind each trap, depending on the trap's contents. In the case of switches and weapons pods, the C64 version plots a unique tile filled with one of the game's background colours; this effectively allows the switches and weapon pods to use four colours (three sprite colours + background) instead of just three. A really simple idea, but extremely effective.

* * *

After a few sessions, the updated graphics were imported, and after tweaking (and simplifying) some of the logic code, all of my 64x64 sprites were in and working perfectly; everything aligns/snaps to the grid, and my trap animations now align perfectly with the background tiles (something which simply wasn't possible using smaller sprites and approximate positioning).

I rounded off tonight's session by tinkering with the force-field doors that will litter the cities (aside: I really need to produce a task list and start getting at least one task per day off my plate). It didn't take long to create an animated object which I can place in the levels, and after adding a couple of lines of code, I was able to stop the enemies passing through them (which now means I can out run the little blighters - at least, until I put in the player/force-field collision!).

Monday, March 17, 2014

Tightening up the graphics...

Tonight's session saw me making a few changes to Citadel's graphics scale. Previously, I was using the C64's resolution, i.e. all my game tiles set to 32x32 pixels. This is all well and good if I merely wanted to emulate the C64 and never zoom in or out; but seeing as I do want to zoom, some changes and tweaks were necessary.

The biggest alteration involved creating a brand new tileset with 64x64 tiles, tweaking the sprite sizes to match, and adjusting the viewport settings within Game Maker to a more appropriate zoom. I also took the liberty of creating a tilesize constant, which I then used throughout the code; in future, should I ever change the tile size again, most of the fiddly work I did tonight will be done for me just by changing one value in the editor.

I rounded off the evening by doing some research into why my tiles were blurry; it turns out that Game Maker only allows texture pages of 2048x2048, and automatically scales images that are too big. So not only were my tiles getting compacted to an eighth of their intended size, they were getting stretched back out again when drawn to the screen. It's often amazing how much a game can be transformed with just a couple of hours' work. Here's hoping this productivity continues. :)


Ohhh Snap!

Another lengthy gap between blog posts, but I can assure you, things in the world of Citadel have been progressing, if a little slower than I would have liked. That said, there has been plenty of procrastination. One of the biggest problems I have right now is focus; I'm so enamored with Game Maker, I see so much potential and have dozens of ideas I'd love to try. The problem with this, of course, is a) not having that much spare time for one project, let alone half a dozen, b) not having eight pairs of hands, and c) I'm not even at what you'd consider an intermediate level of proficiency with Game Maker (yet).

Thus, the only thing I could do to calm the rising wave of "what if's" in my head was to write an orderly list of all the projects I'd like to tackle, and pick ONE that I can tinker with alongside my Citadel remake. It sounds like a plan - I hope by unconscious brain takes the hint.

* * *

 Yesterday I sat down at the keyboard for the first time in over a week, in a vain attempt to get my enemies moving. One of the biggest issues with programming (for me, anyway) is knowing how to break a task down into logical steps. I'd been thinking - and possibly over-thinking - enemy movement and AI for the game, to the point where I had no idea where to start, or what the best approach might be.

In desperation, I'd Googled "enemy movement routines game maker", which ultimately led me to an excerpt from a Game Maker book, where they discussed enemies moving on a tile-by-tile basis (in other words, precisely what I need for Citadel). Key to the routine was the place_snapped command, which allows you to check whether or not an object is aligned to a grid.

After an hour or so at the keyboard (along with a puzzling period of 15 minutes where I was tweaking the code for an object but getting no results; it turned out that I was debugging the code for the wrong object, and naturally, much slapping of the head soon followed), my enemies were finally emerging from traps and chasing me, tenaciously, around the level.

Although some of the graphics will have to be re-imported to work with the grid snapping (essentially, changing the origins of sprites and adding some padding around their edges), the code is starting to take shape; I now have a clearer picture of how the AI/State machines will be structured, and once the movent routines are done I can then allow enemies to start shooting back. :)

Saturday, March 1, 2014

Deep Thought...

A fairly big gap in blog posts, but that's not to say that things haven't been progressing. Much of my time recently has been spent investigating various tutorials and demos in order to work out how Game Maker (GM) handles paths and suchlike; these will be useful for getting the enemies to move around the level and hunt down the player. I could, admittedly, do the hard work myself and use an A* algorithm, but with so many in-built functions in GM, it seems silly to re-invent the wheel without considering all other options.

After a few late-night sessions, and much head-scratching, it became apparent that I'd probably have to use an A* algorithm - great as they are, the in-build functions just won't cut it in terms of what I want to achieve. Luckily, I have a very small and sweet A* testbed created in Blitz+ which I had planned to use for the earlier incarnation of Citadel, so I'll need to set aside a chunk of time to convert it across to GM.

* * *

Today I had a chunk of time to kill, so I spent a couple of hours re-reading Martin Walker's Citadel diary in Zzap!64, mainly to familiarize myself with his thoughts on the enemy AI (I'd previously gone through his diary and written copious notes, but this was a great refresher). It was extremely useful, for instance, to see how he built up the enemy behaviors layer by layer, adding more complex attributes for some of the more advanced enemies (it had completely escaped my mind, for example, that many enemies will follow the player but stay just out of reach of the player's weapons).

* * *

This afternoon, I had planned to take a pass through some of GM's various tutorials; thus far I've been watching some YouTube videos, but  although they're great for covering specifics, it's very easy to overlook some of the fundamental basics, and given that I'd been banging my head against the wall over global/local variables recently, I figured I'd go back to square one.