The Archimedes Gamemakers Manual
Copyright © APDL and Terry Blunt 2002. All Rights Reserved
Chapter 1 - Introduction
1.1 About the Archimedes
The Archimedes has been designed very specifically as a fast graphics machine. At the time of it's launch the only really effective Wimp driven systems were the most expensive business machines. Since then some older command line driven operating systems have had bits bolted on to try and bring them up to date. This is never very satisfactory however.
Many command line driven computers look decidedly clumsy now, often having little by way of programmer support. Hence there tends to be a wide variety of usage and little standardisation of keyboard/mouse handling, file and data transfer or resource sharing. This ultimately makes it harder for the computer user to get the best out of the machine, and is liable to result in programs full of obscure bugs.
There can be very few computer manufacturers in Acorn's enviable position of having designed the processor, its major support chips, the software in the form of RISC OS and many support applications, as well as the overall design of the complete computer system. Thus Acorn have an unusually intimate knowledge of every part of the Archimedes and can give detailed information with a very high degree of confidence.
While the Archimedes was running under the Arthur operating system, and arguably still effectively in final development, Acorn spent a considerable amount of effort persuading the major programming organisations to adhere to their protocols. This included not only the Wimp environment but also the low level interfacing with the RISC OS operating system itself. The success of this strategy has resulted in a powerful, integrated system that is readily expandable both from a hardware and a software point of view. A system well suited for either home or commercial use.
It is doubtful whether there has been any computer that hasn't, at least in passing, had an attempt made to use it for playing games, regardless of whether or not the machine is really suitable. However, the speed and graphic capabilities of the Archimedes makes it a fairly natural choice for modern graphics orientated games. Indeed, although always a dangerous statement to make, it is probably currently the best machine available, being able to deal comfortably with the demands on speed, memory and graphical capability, all at reasonable cost. In fact, the heart of the machine is currently used by a French arcade game manufacturer as its game 'engine'.
An area of computing often overlooked is that of sound production. Acorn have not fallen into this trap but have provided a sophisticated sound system giving eight channels of high quality stereo sound. The Archimedes is capable of utilising complex sound generating algorithms as well as sampled sound data, most of the control being handled transparently in the background. This is remarkable as the Archimedes doesn't have a dedicated sound chip set but works by software control of a relatively simple A/D converter. This makes the Archimedes the ideal platform for developing your ideas into fast, colourful, lively games.
Obviously with all the features available under RISC OS comes considerable complexity, and it is likely that you'll have to spend quite a lot of time getting to know the machine. There is a great temptation to criticise features that appear to be unnecessarily complex, but as you become more familiar with RISC OS you will see that there are very practical reasons for Acorn's compromises, not the least of which is that of maintaining compatibility across an unusually wide range of old and new hardware.
Acorn's policy of maintaining compatibility over different models provides a high degree of confidence that, provided you stick to their guidelines, the game ideas and programming techniques that you develop will be valid for a long time, probably far longer than the commercial life of the games themselves. Acorn make the point that, in real terms, there is absolutely no benefit in trying to use the old peek and poke tricks that were so common in the older machines.
1.2 The Environment
Most of the ideas in this book assume that you are working in Basic. However, Acorn Basic V is such a well structured language that, provided you've developed the habit of using tight, self-contained modules, moving to another high-level language should present few problems. You may be tempted to use one of these compiled languages, or even a compiled versions of Basic. Sacrificing some accessibility can be an advantage as it provides a small degree of copy protection as compiled languages can be quite difficult to disassemble. Also many compilers have facilities to enable you to create relocatable modules or turn your program into a fully self contained application. On the downside, even the Basic compilers currently available are more fussy about things like empty loops and procedure exit points. Some features of Basic V, such as the EVAL function, can't be realised at all. In general with compilers of any high-level language you will need to be more organised in your programming style.
The commonest reason for choosing to compile is to increase execution speed. This will add smoothness and polish in many situations, but if there is a serious speed problem choosing to compile for this reason alone may simply mask rather than cure it, and the difficulties may show up again later. If you have such problems you should either re-consider your data structures or look again at the practicality of your overall game design. Possibly you should move critical sections into assembled ARM code, which is the most efficient form of all. However, neither compiling nor moving to ARM code will make very much difference where the time delays are mainly caused by intensive screen manipulation through the normal VDU drivers.
There are quite a few sections of ARM code in this book. I make no apology for this, as there are some things which it is simply not practical to do in any high level language. The sections of code I've included are so short that you should have no problems using them, even without understanding how they work. In any case ARM code is probably the easiest modern machine language to understand, so once you are familiar with it you may find you actually prefer working from Basic simply in order to assemble fast, efficient, ARM code.
There is a chapter specifically on ARM code for direct screen manipulation etc. This is really aimed at those who already have an understanding of ARM code programming. However, those less familiar with this subject will still be able to make use of the code fragments in this chapter but may have difficulty enacting the ideas described. I recommend that you either follow up by reading through the ARM programming series run by magazines or the ARM programming books.
There are a large number of operating system routines available to you from Basic via SYS calls. These let you really get into the machine and make full use of the operating system with a high degree of confidence that your programs will survive any future improvements in the hardware and RISC OS itself. Those familiar with the older BBC machines will particularly appreciate the ability, in many cases, to pass parameters to and get results back from these calls without the need to set up special parameter blocks.
Acorn use a highly sophisticated system of memory management. One of the results of this is that very few areas of memory are fixed. Where it used to be common to peek and poke memory directly to gain speed advantage or for various special effects such techniques are doomed to failure on the Archimedes. Acorn provide reliable 'official' entry points to all the routines and memory areas you could possibly want to access.
1.3 Programming Techniques
Quite a few of the example program sections in this book are rather crude and unfinished. I've done this quite deliberately so that you can see the principle or idea as clearly as possible. In any case, you're supposed to be writing the game not me! I've also used simple drawing routines instead of sprites for some demonstrations. These wouldn't normally be practical as, even on the Archimedes, they are rather slow, but are simpler to program and easier to follow when demonstrating a point.
As this book is more heavily weighted on games rather than pure programming techniques there are some unexplained details in the program examples. This is, unfortunately, necessary to prevent the book become unmanageably large. The really obscure points are explained, but if you find that some other points seem curious I can assure you that there are sound reasons for them, and that a little experimentation will probably reveal these. If all else fails, look through the relevant parts of the Basic Guide or the Programmers Reference Manual.
You will have to take great care with error checking and input range tests, although I haven't done much of this with my examples. Game players are likely to be careless and inaccurate when thoroughly engrossed in a really exciting game. The keyboard and mouse are likely to be sending all sorts of rubbish to your program so input routines must be bomb proof.
Be wary of using the CTRL key for any game functions as you can get some highly undesirable effects when this key is hit at the same time as others. By default CTRL+[ has exactly the same effect as pressing the Escape key. In fact, it would be wise to completely disable normal Escape key action in the main game loop and have it tightly controlled with error procedures in the rest of the game. You will make yourself extremely unpopular if, in the middle of a particularly frantic starfight, your player sees 'Escape at line 220'.
As well as accidental mistakes you should also make allowance for deliberate input errors. People may enter long strings of digits or numbers to try to make the game crash. By using string input, and checking the length, the program section below completely eradicates this problem. If the player just presses Return or enters letters, or even control characters, the routine will simply return a zero.
UNTIL LEN number$<39
Similarly you should check for mouse button presses by masking the bits to avoid the confusion of two buttons being pressed at the same time. You would then use something like the lines below.
IF (b% AND 2)=2: REM menu pressed
To trap all eventualities use a case statement like the following snippet.
CASE b% OF
WHEN 7:REM select+menu+adjust
WHEN 6:REM select+menu
WHEN 5:REM select+adjust
WHEN 4:REM select
WHEN 3:REM menu+adjust
WHEN 2:REM menu
WHEN 1:REM adjust
OTHERWISE:REM no buttons
There are many situations requiring nested loop structures, which can be a fine opportunity for mixing up loop counters. You should therefore take a fixed policy towards the names of variables used in these situations and their order of precedence. This is shown with the following somewhat contrived fragment.
FOR K%=4 TO 90 STEP 3 : REM only J & I loops inside K
J%-=1 : REM yes it's a loop counter
FOR I%=0 TO 4 : REM no loops inside this one
IF block%(J%,K%,I%)>5 end%=TRUE
UNTIL J%=0 OR end%=TRUE
FOR I%=0 TO 5 : REM not J - it's an inner loop
IF NOT end% THEN count%+=1
Following a series like I, J, K, L, M, ensures that you always know what nesting depth you've reached regardless of the order that the loop variables are used in array indices etc. To be consistent, you mustn't use these variable names for anything else in your program.
It is a good idea to make a point of being consistent with your use of variable and procedure names. Personally, I apply a policy of using lower case letters for all except the resident integers A% to Z%. These I usually reserve for fast loop variables, passing values into ARM code, or for passing values from one program to another. If you keep all other variables to lower case keywords stand out more clearly and there is no possibility of accidentally creating hidden embedded keywords in variables, like the TO in TOTAL%. It is also wise to avoid subscript variables like a1%, a2%, a3% unless there are clear mathematical reasons for their use. These can become very confusing.
Further confusion can result from the use of the underline character in variable names. Although quite acceptable to Basic and giving neat looking words in printed listings it is very easy to accidentally use a minus sign by mistake. Deeply embedded in a nest of genuine mathematical symbols such a mistake would be very difficult to find.
Yet another source of confusion is excessive use of multi-dimensional arrays. It is tempting to try to pack an entire data structure in one array. This is can be very difficult to follow, and in any case is not always the most efficient form either for memory or speed. You are better off using a group of arrays dimensioned to the same size, often referred to as parallel arrays. If a single array is unavoidable then consider using constants for the subscripts rather than numbers. It makes it easier to follow and update if necessary.
Compare the following.
Similarly, where you're obliged to use a single array.
Then in main body of program
I recommend the use of constants generally. For example, you may want to incorporate new features into your game involving adding an extra element to an array. It would be extremely tedious if you had to hunt out every FOR-NEXT loop to change the terminating value where a constant requires only one change.
Often when designing a screen layout, even from a paper plan, small adjustments are needed in the positions of objects to make the overall effect look balanced. If you use constants for things like borders and panels then you will only need to adjust the constants to re-align all parts of that particular group.
MOVE left%+width% DIV 2-halfchar%,bottom%+height%
Although this looks rather wordy you can always thin it down later when you are satisfied with the overall appearance. Many of the examples are spread out like this and significant time and memory savings can be made by compressing the final working program, but always keep a verbose copy for future changes.
Many programmers drop procedures and functions in a program all over the place with no thought given to the overall readability of the program. A better idea is to decide on an order of precedence and stick to it as closely as possible.
A common form is to list these routines in the order that they are called, combined with a nesting level. As this is easier to show than explain here is a typical program framework.
REM ------ Main game loop
REM ----- 1st level routines
REM ----- 2nd level routines
Obviously there is a limit to how far you can take this idea. You may, for example, have your key press function being called from several routines at different nesting levels. You should then put it at a level below the lowest one that calls it.
1.4 Making Notes
Probably the most repeated and most ignored programming advice is that of documentation. I repeat it here, as I believe it is essential for effective programming. It really is important that you make some form of plan. It is also important to make notes of what ideas you get, as you get them, preferably dated, and including the reasons why you decided on any specific course of action. This last is probably the most important of all. In the past I have wasted hours trying to understand a complex piece of code that seems to defy logic, a section of code that I wrote only a few months previously.
When I have a new idea to work on I usually take an informal approach at first. I simply keep a separate folder for each project I'm working on with loose sheets of paper in it. These are dated and dropped in while I think out an idea and try to clarify in my mind the its overall structure. At this stage it is the idea I try to structure, not the program that will eventually result. When I come to develop the program properly I read through all my notes before doing anything. I've learnt from experience to keep these early notes even after I've prepared more organised documentation.
Once you have enough ideas to give you an outline of your game, you should start the proper documentation. Initially, using your informal notes, make out a simple list of exactly what the game is and what it does roughly in order. The example below should give you a clearer idea.
- This game is a combat game;
- There are two teams of opponents (goodies and baddies);
- Goodies are controlled by the player, baddies by the computer;
- There is an option for baddies to be taken over by a second player;
- Fights are between pairs of opponents;
- Any goodie not fighting will be a first target for the baddies to attack;
- Any attacker may fumble and strike itself or a comrade by mistake;
- ... etc.
Lots of people throw up their hands in horror as soon as you talk about documentation, flow charts, and pseudo code. In fact it is much easier to handle these ideas than you might think. In the first place, taking a simple comparison, no-one is frightened by a list of knitting instructions. This is, of course, the documentation, using a specially coded unambiguous set of instructions, for making the garment. in other words a pseudo language. Your knitting pattern will almost certainly have a set of diagrams showing the order in which each part of the garment is to be made and fitted to the rest. This is a clear example of a flow chart.
In brief, pseudo code can be any set of instructions that are completely unambiguous. It doesn't necessarily have to follow any commercial guidelines as it's for your benefit only. A flow chart is a diagram that shows the running order of events, and again there is no need to worry about whether you are using all the correct symbols. Just draw boxes, with a two or three word note explaining what the box is, and arrows leading from one to the next.
In your documentation along with a detailed program outline you should list all procedures and variables that are used. For Procedures and Functions include all parameters passed, noting which ones may be modified. Also give a brief description of the purpose of the procedure. Below is a typical example of this.
Sources spritearea%, spritepointer%(), DATA
Function Creates a table of sprites, reading data from the first line
after the procedure, using workspace at spritearea% and
filling array spritepointer%() with the address of each sprite.
Total number of sprites is in spritetotal%
Results spritepointer%(), spritetotal%
This may seem rather tedious, but in a program of any size that may take months to develop a little time spent on documentation can save hours of frustration. This is particularly true of variable names. It is amazingly easy to chose the same variable name for two different jobs, resulting in the most obscure bugs. You should do this work as you develop the routines. If you leave it till later you will almost certainly have forgotten important points and will probably find the task of documenting 40 or 50 routines a daunting prospect. If you are fortunate enough to own two computers you could have the second one set up as a wordprocessor for instant access. I sometimes use an elderly BBC Model B for this.
Once again, keep your earlier documentation. If flaws develop in your logic, then if you have kept as much detail as possible while developing your design, these problems will be easier to follow back to their source.
There are two distinct schools of thought regarding comments and remarks within program listings. On the one hand you may be advised to sprinkle your programs liberally with remarks, but at the other extreme you'll be told that you should keep all your comments in the main documentation.
If you intend to compile your program then you can probably afford to be pretty liberal with comments, although too many on one block of code can, instead of being an aid, become quite confusing. Where you are running interpreted Basic, the situation is quite different. Any extra text in the program both consumes processing time and memory. Therefore it is probably best to make more detailed documentation and keep your programs clear and uncluttered.
I have put very few comments in the listings in the book. This is to save you typing. Besides, the book is the documentation!