Part 9. Wings, engines, turrets and guns.
Programming The Spectrum.
I had a few machine crashes over the last month probably due to Windows updating as I was keying in changes. It reminded me of the days when I typed my program into the Spectrum an one extra hard press or a power fluctuation was all it needed to reboot. Andrew's Dragon 32 and Commodore 64 were much more robust. I can remember once he had dome something to freeze the C64 so I had the bright idea of trying to create a power surge to reset the machine. Then he could save his data as unlike the Spectrum the memory would be intact. I tried creating a power dip by switching on a 2k electric fan heater on the same extension lead.
I can remember when the Spectrum arrived in its box with its two manuals. There were only a few bits useful to machine code programmers. It explained how you could lower the address of the limit of the Basic to give you room to put in a machine code program. The it was a matter of finding a way to poke the machine code bytes to the room you had made. I realised that entering it as decimal in poke commands was a waste of time. There were no assemblers available at first and when they appeared they were so large there was little room for the machine code. I decided to adapt a hallway approach . I entered the machine code in HEX as REM statements using the Basic editor. I used 4 letter labels to make amending the code easier.
10 REM LSUBC
15 REM 3A@LIVE
20 REM 3D
25 REM 32 @LIVE
30 REM C9
The L symbol on the first line denotes SUBC is a label. The @ symbols denote references to labels.
I had to write an assembler program to load in the assembler. The original was a series of pokes in a Basic program. Once that was working typed the same program in as hex as described and got it to load itself. This made it easier to amend. Using a program to develop itself is quite fascinating, I have often wondered what the minimum bootstrap code you would need to amend itself and develop into any program. I suppose that's a bit like the beginning of evolution.
Having labels was the key to this system. It allowed me to add lines of coding without having to go all through the program and change all affected addresses. Later I hacked a disassembler to allow it to use my label data and use a Centronics printer and also . I could at least then print off source code to check my coding and assist debugging. It also allowed me to save or load blocks of the completed code or data
I soon got to know all the hex codes for common Z80 instructions. Although hand assembling was a bind there was hardly anything to type. This meant it was quick to input and more importantly did not take up too much room. You needed enough room for the machine code. After the code had loaded the Basic was reduced to a minimum size and its place used for variables and work areas. Sometimes the program hex had to be split into more than one load , usually near the end of development.
It was one of the reasons I used small test graphics until late in the development. It was a pain having to do multiple loads from tape and getting all the addresses correct.
I was looking at the mastering instructions for Seiddab Attack. It involved 16 steps of loading, saving and a couple of alterations of the Hex Autoloader to load the code in different places. It had to be done really carefully using correct versions of each part and correct loading and saving addresses and sizes.
Its been a hard month. I started off glad to get back in the main program rather than working on the part editor. Although I got the parts joining up pretty quickly I ran into all sorts of challenges when I tried a more complicated ship with wings, guns and engines. I thought I had the 3d orientation cracked but I had not considered parts with side joins. They kept coming out at funny angles until I realised I needed rules for the different sort of joins. Hulls with end joins need to turn around the Z axis to face the correct direction to join. Some parts such as engines have to roll until the join meets the side join on the hull.
When I tried to test this out I found the connections had stopped working. I realised my editor was losing data I had carefully placed to specify where the joins are. It took me a few edits to realise the data was not being saved correctly. I had used a dirty bit to signal when fields changed and forgotten to set it for all the new fields. So the editor looked like it was working but failed to save some critical data.
"That's the thing when you are the only programmer you cannot pin the blame on anyone."
I also found that my meta data driven save still had a few bugs in the saving of complex structures such as arrays of arrays. It was amazing I had not spotted that I had mixed up the type of the collection with the type of the collection contents. I had tidied the code to add linked lists but missed out a test case when checking. It was the kind of error that bites you later when you have forgotten whet you did. I use GIT source control to track changes. Whenever something stops working it pays to look at the differences. That's the thing when you are the only programmer you cannot pin the blame on anyone. You just have to think, how do I stop myself from making the same mistake.
Adding The control Panel
I added a grid control to show all the spare slots in each part of the hull. When a slot is selected all the suitable parts are displayed on a carousel which can be moved back and forth. I added a display of the current items details which depended on the class of the item. That took much typing of structures meta data and input fields but was soon completed using my data display system. The organisation of display fields in sub windows is proving very useful. I have shuffled the screen positions a couple of times just by repositioning sub windows. All positions are relative within a parent window and windows can be nested. I love it when a plan comes together.
Magic Moments.
As each part of the ship has a weight I thought it would be cool to use these to calculate a centre of gravity to move the ship around. Back to basic Physics. I wrote out the moment formula and then the sum of all the moments. I then did a bit of algebra to get all the variables on the right and put the resulting expression into code. I added the routine to my 3d object routines as it is very reusable. To test it I tried adding various parts with different weights and turning the ship. After a few false starts I soon had it rocking and rolling.
I could now piece together a hull, add engines wings gun turrets, engines and guns. even though the test parts were just thrown together with a scratch texture the results were looking good. With just a few basic parts I could get many types of ship. Most of the basic functionality was there so it was time to save file of ships and load them into the game. I hadn't saved out a designed ship for a while and found it almost worked. That same save routine still had a mistake in it, two lines in the wrong order: how did that happen? Sometimes I find the cursor moves code around when I'm not looking trying to catch me out when my thumb brushes the mouse pad. I find with Windows 10 and VS2012 so many things are popping up all over where yo are trying to read it can be really confusing. Doesn't the machine know I am trying to read and type.
"I spent a few nights flying round and blowing them up"
I got the designed ships flying about in the game. It looks so different having my own graphics. That took a few months of grind so I spent a few nights flying round and blowing them up. The look is starting to be like I imagined. On a roll I went back to the editor to add a few more parts. Back to the game and its all screwed up. I realise I have lost a data file. In my editor I was saving in a different directory in case the save failed and I forgot to copy the file to the load directory. I must write a backup system for the editor and game saved files next month.
I had a few machine crashes over the last month probably due to Windows updating as I was keying in changes. It reminded me of the days when I typed my program into the Spectrum an one extra hard press or a power fluctuation was all it needed to reboot. Andrew's Dragon 32 and Commodore 64 were much more robust. I can remember once he had dome something to freeze the C64 so I had the bright idea of trying to create a power surge to reset the machine. Then he could save his data as unlike the Spectrum the memory would be intact. I tried creating a power dip by switching on a 2k electric fan heater on the same extension lead.
I can remember when the Spectrum arrived in its box with its two manuals. There were only a few bits useful to machine code programmers. It explained how you could lower the address of the limit of the Basic to give you room to put in a machine code program. The it was a matter of finding a way to poke the machine code bytes to the room you had made. I realised that entering it as decimal in poke commands was a waste of time. There were no assemblers available at first and when they appeared they were so large there was little room for the machine code. I decided to adapt a hallway approach . I entered the machine code in HEX as REM statements using the Basic editor. I used 4 letter labels to make amending the code easier.
10 REM LSUBC
15 REM 3A@LIVE
20 REM 3D
25 REM 32 @LIVE
30 REM C9
The L symbol on the first line denotes SUBC is a label. The @ symbols denote references to labels.
I had to write an assembler program to load in the assembler. The original was a series of pokes in a Basic program. Once that was working typed the same program in as hex as described and got it to load itself. This made it easier to amend. Using a program to develop itself is quite fascinating, I have often wondered what the minimum bootstrap code you would need to amend itself and develop into any program. I suppose that's a bit like the beginning of evolution.
Having labels was the key to this system. It allowed me to add lines of coding without having to go all through the program and change all affected addresses. Later I hacked a disassembler to allow it to use my label data and use a Centronics printer and also . I could at least then print off source code to check my coding and assist debugging. It also allowed me to save or load blocks of the completed code or data
I soon got to know all the hex codes for common Z80 instructions. Although hand assembling was a bind there was hardly anything to type. This meant it was quick to input and more importantly did not take up too much room. You needed enough room for the machine code. After the code had loaded the Basic was reduced to a minimum size and its place used for variables and work areas. Sometimes the program hex had to be split into more than one load , usually near the end of development.
It was one of the reasons I used small test graphics until late in the development. It was a pain having to do multiple loads from tape and getting all the addresses correct.
I was looking at the mastering instructions for Seiddab Attack. It involved 16 steps of loading, saving and a couple of alterations of the Hex Autoloader to load the code in different places. It had to be done really carefully using correct versions of each part and correct loading and saving addresses and sizes.
Deepest Blue Progress.
Its been a hard month. I started off glad to get back in the main program rather than working on the part editor. Although I got the parts joining up pretty quickly I ran into all sorts of challenges when I tried a more complicated ship with wings, guns and engines. I thought I had the 3d orientation cracked but I had not considered parts with side joins. They kept coming out at funny angles until I realised I needed rules for the different sort of joins. Hulls with end joins need to turn around the Z axis to face the correct direction to join. Some parts such as engines have to roll until the join meets the side join on the hull.
When I tried to test this out I found the connections had stopped working. I realised my editor was losing data I had carefully placed to specify where the joins are. It took me a few edits to realise the data was not being saved correctly. I had used a dirty bit to signal when fields changed and forgotten to set it for all the new fields. So the editor looked like it was working but failed to save some critical data.
"That's the thing when you are the only programmer you cannot pin the blame on anyone."
I also found that my meta data driven save still had a few bugs in the saving of complex structures such as arrays of arrays. It was amazing I had not spotted that I had mixed up the type of the collection with the type of the collection contents. I had tidied the code to add linked lists but missed out a test case when checking. It was the kind of error that bites you later when you have forgotten whet you did. I use GIT source control to track changes. Whenever something stops working it pays to look at the differences. That's the thing when you are the only programmer you cannot pin the blame on anyone. You just have to think, how do I stop myself from making the same mistake.
Its All Done With Mirrors
I wrote a whizzy routine to mirror a 3d object mesh when I needed a left and right handed version. Its one of those routines that almost works. Well, it looked ok when I tracde it but came out in the game really weird. The graphic is in a series of tri strips. I had negated all the Y coordinates of the vertices and also swapped the bottom and top vertex references in the tri strip as mirroring the strip would cause all the tri's to be in the incorrect order for visibility. I spent several sessions trying to sort this out. It turned out that I was not even mirroring the correct object so the data I carefully traced was not even used. Once I spotted that things started to fall into place. I noticed my maths had failed me, I had recorded the wrong number of tris. It still gave strange results but at least was giving me a recognisable graphic. I drew a sample tri on paper and realised you couldn't just turn it upside down or even left to right to reverse the order of vertices. you had to shift all the vertices along by 1 . Finally I was there. That's the thing with 3d. Some things look so simple and intuitive but turn out to be really difficultAdding The control Panel
I added a grid control to show all the spare slots in each part of the hull. When a slot is selected all the suitable parts are displayed on a carousel which can be moved back and forth. I added a display of the current items details which depended on the class of the item. That took much typing of structures meta data and input fields but was soon completed using my data display system. The organisation of display fields in sub windows is proving very useful. I have shuffled the screen positions a couple of times just by repositioning sub windows. All positions are relative within a parent window and windows can be nested. I love it when a plan comes together.
Magic Moments.
As each part of the ship has a weight I thought it would be cool to use these to calculate a centre of gravity to move the ship around. Back to basic Physics. I wrote out the moment formula and then the sum of all the moments. I then did a bit of algebra to get all the variables on the right and put the resulting expression into code. I added the routine to my 3d object routines as it is very reusable. To test it I tried adding various parts with different weights and turning the ship. After a few false starts I soon had it rocking and rolling.
I could now piece together a hull, add engines wings gun turrets, engines and guns. even though the test parts were just thrown together with a scratch texture the results were looking good. With just a few basic parts I could get many types of ship. Most of the basic functionality was there so it was time to save file of ships and load them into the game. I hadn't saved out a designed ship for a while and found it almost worked. That same save routine still had a mistake in it, two lines in the wrong order: how did that happen? Sometimes I find the cursor moves code around when I'm not looking trying to catch me out when my thumb brushes the mouse pad. I find with Windows 10 and VS2012 so many things are popping up all over where yo are trying to read it can be really confusing. Doesn't the machine know I am trying to read and type.
"I spent a few nights flying round and blowing them up"
I got the designed ships flying about in the game. It looks so different having my own graphics. That took a few months of grind so I spent a few nights flying round and blowing them up. The look is starting to be like I imagined. On a roll I went back to the editor to add a few more parts. Back to the game and its all screwed up. I realise I have lost a data file. In my editor I was saving in a different directory in case the save failed and I forgot to copy the file to the load directory. I must write a backup system for the editor and game saved files next month.
Programming Tip. Avoiding Recursion.
When dealing with parent child systems it is really tempting to write a routine or routines that call themselves recursively. This has a couple of disadvantages. Each recursion causes stuff to be added to the stack to maintain the call and pass parameters, also room for local variables. This can make it slower than coding a loop. Also recursive programming can be tricky to debug as it can be hard to keep track of what level you are debugging. When you get used to it using a loop can be much better but it does take a bit of practice. So for illustration consider a tree of parent /children objects. What we do is consider the structure of the hierarchy as
Tree consists of
Levels consists of
Objects
To facilitate the traverse of the tree we need to store the level count we are currently processing and the current object address. To be able to return to previous levels during the traverse, when we have finished all the children of an object have to store the address of each parent in an array which will be indexed by level.
In pseudooode
Set Index to 0
Set CurrentObject to top object
while CurrentObject is not null
Process Object
If CurrentObject has children
Store CurrentObject in ObjectStore[Level]
Increment Level
Set CurrentObject to first child of CurrentObject
ends if
Set CurrentObject to next object (or NULL)
while CurrentObject is NULL and Level >0
decrement Level
Set CurrentObject from ObjectStore[Level]
ends while
ends while
I find this structure crops up all over the place so is a useful one to code then copy as you need it. To make it faster you can get rid of using the store with an index and just use a roving pointer that is incremented and decremented in place of the index. Note the routine processes the prent before the children. Occasionally you need to process children first. The you need to remove the Process object and place it in a couple of places , when the current object has no children by adding and else, and also when the current object is set from the object store.
Comments
Post a Comment