Skip to main content

My God, it's full of stars...

Here I am once again out in the wilds of Central Asia and today, with a few hours to kill waiting for a connecting flight, I struck upon a new approach to an idea that I'd been thinking about for a while. I wanted to look at the AGD Starfield routine and see if I could enhance it in some way.

I'm not going to get into the exact ins and outs of the whole routine, but essentially there are five types of particle that can be generated in AGD - a horizontal laser, an explosion pixel, a trail pixel, a horizontal scrolling pixel, and a vertical scrolling pixel. Each one has its own routine that controls its movement - for example, explosion pixels spawn at the explosion point and have a random 'outward' angle. Trail pixels are spawned at the current co-ordinate, and slowly trickle away.

Horizontal 'stars' are pixels which are spawned at the right side of the screen, and move from right to left, and of course Vertical 'stars' start at the top of the screen and scroll down.

Obviously, the starfield is the simplest of the routines and this is the one I'm looking at today - specifically the vertical. There are two things I hope to achieve - firstly I want to create a 'multi-speed' starfield which gives a feeling of depth similar to parallax scrolling, and secondly I want to be able to give the player or coder some degree of control over the speed of the stars, to give the impression of acceleration / deceleration.

Again. not going to get too technical here, but basically each pixel is part of an array which tells us what kind of pixel it is, whether it's active, where it is on screen, the direction it's moving in and so on. These are all accessed using the IX register, and the routine for moving the pixels vertically is as simple as this:

inc (IX+3)
ret

Obviously, other checks are carried out such as whether the pixel has gone off screen, but these routines are run on all pixel types as part of the AGD particle engine, so this is all we need concern ourselves with for now.

Obviously, if we wanted to increase the speed of the starfield, we could do the following:

inc (IX+3)

inc (IX+3)
ret

Which would double the speed since we would be increasing twice. The problem we have, however, is that if you change the core engine of AGD, it almost always affects the memory map, and all previous games become incompatible. This means it's very difficult to add code directly. However, what you can do is divert the existing code elsewhere. In essence this means finding a call routine used within the routine we want to amend, changing it so it goes somewhere else and runs our code, then returns to where it started none the wiser. In a sense it's a little bit like jailbreaking a console, where you redirect the machine to your own code.

Fortunately Jonathan Cauldwell very kindly allowed me access to the AGD source code, which makes life a lot easier. Each particle type has its own routine, which in turn has its own address, which in turn is defined by a pointer.  Here's the source code.

What we have here then, is a list of addresses for each routine, which is perfect, because all we need do is change the address for the vertical starfield routine, and we can run our own routine in its place.

The routine can be put anywhere that memory is free, but as with a lot of small routines I write to enhance AGD, I usually put them in the game font so they can be easily tested without disrupting any other code. In this case I'm putting the routine in at 31704. So I have to change the address for the vertical starfield to use my own routine. The pokes needed here are:


poke 32967,216 and
poke 32968,123

You can try this yourself, just make sure you have working code at address 31704 - code which might look like the routine I'm now going to look at. The trick I want to try here is relatively simple in concept, but should look quite nice, and shouldn't slow down the process too much.

We know that when the particles that make up the starfield are spawned, they start from a random horizontal co-ordinate, and then move down vertically. So what I plan to do is use that random horizontal co-ordinate to affect the speed of the pixels. In a sense this will work like lanes of traffic - there will be fast lanes and slow lanes depending on where the pixel is spawned. This is achieved by taking the first two bits of the horizontal co-ordinate and using this as our speed. For example, if the pixel has a horizontal value of 163, this would be 10100011 in binary. By using 'OR 3' we can take the last two bits ('11' = 3) and this means the pixel is in the fast lane. 162 would give us a value of '10' or 2, 161 a value of 1. The lower the value, the lower the speed of the particle.

And there was me promising not to be too technical! Well, needs must. What's important to understand here is that by looking at the number in this way, we effectively create four repeating 'lanes' of pixel traffic on the screen - and by adding the number of the lane to the vertical co-ordinate, the pixels will move faster or slower depending on the lane they are in. The advantage of this is that it uses data which is already available to us (the pixels always have the same horizontal co-ordinate), which in turn means the amount of code needed is minimal, which then means greater efficiency.

Let's take a look at the code:



As you can see, the routine takes the last 2 bits of the horizontal co-ordinate to determine the particle speed. In addition, we add 2 to this total (inc a twice). The reason for this is that we have numbers 0 to 3 - we want our starfield to move so adding zero isn't a good idea, and if we increase the whole thing by two it will move a little faster all round, and the contrast between the different speeds won't be so pronounced. What I mean by that is if we used numbers 1,2,3 and 4, then the second lane would be twice as fast as the first, and the fourth lane would be quadruple. By using 2,3,4 and 5, we lower that ratio considerably, which will look better on screen - if you've read my blog on 'breaking the spell' you will perhaps know what I mean here - if some pixels are moving far more slowly than others, it will jar with the player and be a distraction.

So, that's our code, and at only 16 bytes it's easy to find a space for it. So we open up the charset in AGD and load the compiled routine in at 31704. Since we've already poked the engine, we don't need to call this code in the script - AGD itself will now redirect to it. And this is the result.




As you can see, this is pretty much what I was hoping for. It's also worth noting that another advantage of this method is that we get a nice even distribution of stars of different speeds - they are never 'stuck' together, and are nicely spread - again, no jarring.

Giving the player control over the speed is actually relatively straight forward and we'll look at that in a (shorter) entry very soon. Until then, as always, Happy Coding!

P.S for those that missed it, the title comes from a reference to the Kubrick classic 2001: A Space Odyssey. Utterly unable to determine the difference between the literal and the figurative, the Googlebots appear to think I'm being religious so apologies if the YouTube video is pointing you in that direction.


Comments

Popular posts from this blog

Destructible levels

Ok, so I've been thinking over the idea of destructible levels in AGD for a while now. Basically the idea is to have a more advanced equivalent of the 'fodder' block - this kind of block can be destroyed by the player in game. The problem with this however, is that these blocks are restored when the player returns to a room. This means we can't create levels for players to open up themselves. What we want here is the ability to preserve the blocks that have been removed so that when you exit a room and then come back in, they will not be restored - they will remain the way that the player left them. This opens up the possibility of areas of game being inaccessible to the player until they dig or blast their way through. So, what are the considerations? The first and most obvious consideration is that we will need to store the changes made to the rooms somewhere. This could take up a lot of space quite quickly if we don't plan it properly. At the same time, it will

Welcome

Hello there happy coders. I'm currently in a cheap hotel room in the Northeast of Bishkek, Kyrgystan. Watching the world cup, living mostly on green tea and cherries. Seems like a good time to start a code blog...