|You don't have any items in your cart|
|Subtotal (ex. VAT)|
After adding in lights to the game, I set about expanding and developing a bit more the enemies and magic/inventory for the player. I also set about creating a proper HUD to show the controls on devices as well as the player information - health, gold, the current level and whether they had a key or not (I had also made it so that certain levels are "lockable" and require a key to leave, hence the space for a key in the HUD). I'll talk a bit more about these additions in next weeks blog, but this week I want to talk about a small crisis I had while working on these things...
I had what I felt was a pretty solid start to my game. Lighting worked well, enemies did what I wanted, the basics for the magic system were in place and my dungeon generation was awesome... so why wasn't I happy?
At the time I started to make my action RPG game, the GameMaker: Marketplace had more or less just opened and it was getting some pretty interesting stuff thrown up. In particluar there were a few lighting engines on there that use shaders to create dynamic lights and shadows from instances or tiles, and these interested me greatly as good 2D lighting in GameMaker has long been a "holy grail". So, I dug into my PayPal account and downloaded two of the best looking ones to test with my project...
To tell the truth, I was pretty excited by this, as I remember old GM users like GearGOD or Adventus creating super complex lighting engines in GM6 which looked absolutely gorgeous but were complex as hell:
At the end of last weeks diary, I was just getting to grips with the player movement and some basic controls, and I'd decided to use a grid-based approach to collisions. With that working it was time to move on and start breathing some life into the enemies in the game, which meant that I was going to have to start working on one of may favourite parts of developing a game... the AI.
When I start to code the AI for a new game, I generally don't ever rely on previously made frameworks or scripts from other games. I've found that each game requires a unique solution and that if you want it to work correctly and do what you require, then the only way to go is to build it from scratch. That doesn't mean to say I don't look over the rather large number AI demos and scripts I have lying around as they provide a valuable resource for ideas and techniques as well as fast-prototyping, but I generally start from zero and just take snippets that are appropriate (you can find a load of my old GM7/8 AI stuff - as well as other tech demos - from here if you're interested, but beware! It's all quite old and probably a mess...)
With the basic design of my HUD finished, and the core dungeon generation code working well, it was time to move on and get stuck into the core gameplay mechanics. This would have to start with the player, as the decisions I took about how the player moves and how it reacts to the environment would later shape other gameplay features like the enemy AI, or item placing, etc... So, it was finally time to add a player object to the game world!
Moving from Stable 1.4.1474 to 1.4.1567
We will shortly be updating the version we have set to the Stable channel to be the recent 1.4.1567 release currently live on the Beta channel, and there have been an awful lot of changes and improvements made in the last run of Betas since 1.4.1474, so I thought I’d take you through some of the key things to be aware of as you upgrade to the new release.
In the last blog, I explained how I created the walls and doors of my dungeon, as well as how I added in some initial graphics to see how it all works together. The results were better than I could have hoped for, especially after I added in some optimisation, but having a nice looking dungeon isn't really much fun if the player can't see it properly, so in this weeks tech blog I'll be talking about the decisions I took for setting the view size and aspect ratio as well as the GUI layer.
At this point in the project I had to start to take some hard decisions, namely:
For some time we've had requests to make some of the graphics pipeline more visible, so that developers can get things like the order of texture page usage, the size of vertex batches and even helping to debug shaders. The reason we've never bothered with these, is because theres already a tool that does this for you, and gives you more than we ever could - PIX.
Pix is a little temperamental to start up however, so I'll give a little walkthrough on using it with a GameMaker: Studio project. We'll use the Angry Cats Space demo for this so let's fire up Studio, select the Demos tab, open up the Intermediate folder, and select Angry_Cats_Space.
After creating the base of my new game engine (see last weeks tech blog on procedural generation), it was time to start to bring the game world to life. This meant taking the data I had generated for my dungeon and turning it into instances in a room so that the player actually had something to interact with. So, in this weeks diary, I'll be explaining how I went about this, as well as talking about some of the challenges I faced and the techniques I used for optimising things.
At this point in development I had my dungeon generator creating a DS grid, the cells of which were being flagged with different values that I'd assigned to macros - currently g_wall (0), g_empty (-4), g_door (1) and g_corridor (2) (using macros in this way helps keep "magic numbers" out the code base and makes the code clearer to read, so don't forget to use them!). This setup meant that all I really have to do is a couple of "for" loops to go through the grid a cell at a time checking it's grid value and then creating an instance relative to the grid position that's been flagged.
In last weeks tech blog I went into some detail about the creative process behind making a game, and came to the conclusion that I wanted to make an action rogue-like (ARPG) in the style of the classic Gauntlet. So, I have my design brief with a list of things that I want to achieve and at the top of the list is the procedural creation of dungeons for our player to explore...
When it comes to generating procedural content, there are a few problems to overcome and some hard decisions to make, but the main one is how to produce the content! Since I'd never really done procedural generation of any type in my games, I obviously had to research the subject a bit, and my first port of call was downloading the Spelunky source. Spelunky is the great grand-daddy of procedural GM games, and one of the most well known aspects of it is the way it creates a random room for the player from some pretty simple rules... so I wanted to check it out and decide if this was something I could implement for myself.
This weeks tech blog continues on in the spirit of the previous ones that Mike Dailly has written, only instead of taking a look at the development of an emulator, we're going to be taking a look at creating an actual game from start to finish. The game in question is one that I have been wanting to make for quite some time and is in fact a return to my roots using GameMaker...
The idea for my game comes straight from my youth - Gauntlet and Gauntlet II. I loved those games! I loved them so much, that the first thing I ever made with GameMaker was a Gauntlet clone (hey, we've all cloned our favourite games, right? Best way to learn...). I've progressed quite a bit since I made my Gauntlet fan-game, and now tend to make smaller, mobile-friendly games that are on a less epic scale, but that game still holds a special place for me. To be honest, I've been wanting to revisit the idea for a while now, especially as GameMaker: Studio has better performance than the GM7 that I used to make my own fan-version... meaning more of everything. More effects, more gameplay and more enemies! So, that was decided then... I was going to make a game inspired by Gauntlet!
So if you followed my last emulator series, you'll know that I built up a lot of caches of shapes (characters and sprites) on demand, and then drew them when required. This works great for old consoles, and computers with character map screens, because on the whole, games tend not to change character set images very often, just the actual character map screen, which referenced these images. Because these kinds of machines have pretty good hardware support, they don't have to resort to shifting bitmaps around, there are much easier ways of doing things.
On a ZX Spectrum however, we have a single bitmap screen, with no hardware support at all. This means as soon as a game scrolls, the whole screen changes, and you'd have to refresh the entire cache. Sure, there would be lots of games that worked just great - Manic Miner, Monty on the Run - single screen platformers for the most part, but nothing that scrolled.
So in this, the last part of my Commodore 64 Emulator series, I want to talk about some of the optimisations I did to help speed things up. But before getting into this, why do we need to speed things up? Wasn't it all running at 100fps+ anyway? Does it matter if your already over 60fps, as this is the refresh of the monitor? Well, yes and no.... No once you're over 60fps, its not that going to show any real difference. And yes... it does matter, because when things "hicup" the more spare capacity you have, the easier it is to absorb the hicup.
Lets say we've gotten everything to run at 60 - just, but running nice and smoothly. All of a sudden the game changes a lot of sprites/characters, and we drop 20fps. This means the overall frame rate has dipped to 40fps, and this means it stutters and slows down. But optimising and getting the FPS up to as high a level as we can, it'll smooth out these blips, and run on lower end hardware than we're using - there's always someone with worse hardware then you.
So in this chapter, I thought I'd tackle the tricky subject of SID chip emulation, both how I generate the sounds, and how I get them to play back in GameMaker. Before getting into any of the nitty gritty, let's have a quick look at the SID chip itself. Back in the day, it was the sound chip, the sound it generated was unparalleled in computers, and the musicians that created music on them - Gods among developers, superstars in their day. So what can this masterpiece of engineering do?
It's a 3 channel engine chip of playing Sawtooth, Triangle and Pulse waveforms along with a white noise effect, all controlled through hardware based ADSR (Attack, Decay, Sustain and Release) volume control system. It could also do some amazing effects via ring modulation and high, band and low pass filters. My somewhat simple emulation doesn't currently deal with ring modulation, or the band filters, but you still get some amazing sounds from the basics.
So, now that we have C64 sprites being rendered, how about characters? Well like sprites they are made from blocks of memory on even boundaries, all be it a lot smaller. So we can do the same trick with invalidating and caching on demand 8x8 surfaces. So how many 8x8s can a C64 hold? Well...8,192. That's a fair old step up from the 1024 that Sprites used. So can we fit 8,192 characters on a surface? well, as it turns out they fit nicely on 1024x512 surface, which isn't too large at all these days.
So, just like sprites, when the CPU "pokes" into memory, we take the address, divide it by 8 (a single C64 character takes 8 bytes), then flag that block as invalid. Once this is done, we can use the screen drawing loop we created before, and for each character we read from screen memory, work out it's actual address, divide it by 8, and check to see if we need to refresh it. To work out a characters actual address, we take the base address of the currently selected VIC bank; it can be one of 4 addresses - $0000, $4000,$8000 or $C000, and add on the base on the character set within that bank. Character sets can in one of 8 locations in each 16K block: $0000,$0800,$1000,$1800...up to ....$3000,$3800. Once we have the character set address, we simply get the character code (0 to 255), multiply it by 8, and add that on as well to get the actual character bitmap address, then divide the resulting number by 8 to get our character "slot", at which point we can check to see if it's memory has been written to, and if so we rebuilt the character.
In this part, I'm going to start looking at sprites, and see if there's anything I can do in order to display "something" so I can better see games running. The simplest thing to do, is to just display a blob, but before we do that let's look at sprites in general.
The C64 can have 8 hardware sprites, and each sprite is 24x21 pixels in size. They're such an odd size because by making them this size, it means they'll take up 63 bytes, and this in turn gives it a nice boundary for the hardware to render from (a sprite shape every 64 bytes). The first 3 bytes make up the top row, while the next 3 row 2 and so on... in HIRES mode, 3 bytes (8 bits per byte) gives 24 pixels, while in MultiColourMode (MCM), the resolution (but not size) is reduced to 12x21. This because it takes 2 hires pixels to make one MCM pixel. Since 1 bit gives 2 values (0 or 1), 2 bits gives us 4 values (0,1,2 and 3). This means MCM mode gives us 3 colours and a transparent background, although 2 of the colours are shared between all sprites. Each sprite can have an X and Y coordinate ranging from 0 to 511 on X, and 0 to 255 on Y; however there are hidden areas to allow you to smoothly bring them on and off the screen - as shown below