Okay, okay - so Skyrim came out.
I apologise.
Also, I've been incredibly busy at work (live fixes FTW! feels like I'm in the games biz still! XD)
But... yes.
This project is still alive. I did mention it might be... lethargic :P
I have not given it up. It still has a dedicated machine... and a dedicated fan.
Give me up to a week - and I will resume. Or less, if MFC (current project, grrr) annoys me enough...
(And what do you MEAN that Minecraft went 1.0? No, no... I'm sure it couldn't be that... or that an old friend from before I was even *in* games set up a server for said game... Nosir! Never! NEEEEVEEER!)
Monday, 21 November 2011
Tuesday, 8 November 2011
Arx Fatalis Build - Day 2
I suppose I should stress early on that this Arx Fatalis experiment is merely a minor side project... but with determination! (Just in case progress seems... well, a bit lethargic...)
That said, day two's progress:-
Got the DirectX August 2007 SDK in place - only to find that I now (seemingly) need the (probably older) Windows SDK download too (the Windows 7 version of the files seem not to like the project very much... or vice versa, in fact).
All this old crap floating around on Windows 7 is beginning to concern me... Might need to dig out an old PC for this work or summat... (Just in case)
I may still try it on this machine later, once I've completed other more pressing tasks (i.e. work, etc.)
Incidentally, for those thinking: why not just change the project(s) to use DirectX9 or later, and the more recent Windows SDK?
Simple answer: it will probably take longer to do that on its own that the changes I want to make to the game - and it might not work as intended either, dragging me into a much more frustrating "porting" exercise. Also, if I were to do this sort of work, it is more likely I'd change it over to OpenGL so I could later do a Mac port... (And I'd definitely not move it to DX10 or higher, because it then won't run on XP).
Needless to say, I'm not immediately planning to do any of that ;-)
But I will definitely keep on with the original aims (even if it means beating an old PC into submission first...)
EDIT:
Going to use my retired copy of Windows XP (32-bit) and VS 2008 (probably) on a creaking Pentium 4 system that has no graphics card slot (it has Haiku Alpha 2 on it right now... that at least flies! :-D)
That way, I can frak about with all kinds of rubbish from 4 years ago, without destroying my now-quite-comfy-thank-you work dev environment...
Installing Windows XP after all this time... Wish me luck!
EDIT 2:
Woo! This PC is actually pretty nice for dev, given its age! 2.96GHz Pentium 4, 2GB RAM... Shame about the graphics card... or lack of one.
Also, shame the DVD drive sounds like a f***king F1 car... I tell ye, it's got gear changes and everything!! ... Sounds like Silverstone...
EDIT 3:
Yeah, I think that internal DVD drive is dead.
Bit much when my external USB drive does better than IDE directly (a really, really slow drive I originally bought for my dreadful Samsung Netbook... thing... and then, later used on the MBA until I realised it was quicker to use the remote drive on the iMac...)
EDIT 4:
So! P4 machine running and building Arx :-) Even in Debug, it runs well (including font rendering, oddly) which proves - if such proof be needed - that it is not a slow game in and of itself... Some hunting no doubt required to solve these issues...
EDIT 5:
And in Release, it runs superbly well, even on this awful integrated Intel graphics card! Might as well just play it on this machine instead :-D
But no fear, I will still endeavour to investigate these mysterious issues on more modern machines... Starting tomorrow ;-)
Oh, and in case you're wondering... Yep, magic is now a doddle to cast!
EDIT 6:
D'you know... The issue with casting might actually be as simple as the application not taking account of the Windows mouse speed settings?
Using the Apple Trackpad started me on this line of thought - it was so much easier to cast spells on the game with it... Then I noticed it's tracking speed was not the same as the Intellimouse (same mouse on both the new machine, and the P4 machine)...
So I changed the speed in *Windows* to the half way point, which I think is default...
Suddenly, magic casting worked. Really should have tried that sooner ;-)
So, using the normal Windows application API calls for the mouse might solve this automatically for all machines, if lucky - I will add some code to the game startup to do this tomorrow at some point, and see what it does.
Doesn't solve the font issue, but at least the game is playable now!
That said, day two's progress:-
Got the DirectX August 2007 SDK in place - only to find that I now (seemingly) need the (probably older) Windows SDK download too (the Windows 7 version of the files seem not to like the project very much... or vice versa, in fact).
All this old crap floating around on Windows 7 is beginning to concern me... Might need to dig out an old PC for this work or summat... (Just in case)
I may still try it on this machine later, once I've completed other more pressing tasks (i.e. work, etc.)
Incidentally, for those thinking: why not just change the project(s) to use DirectX9 or later, and the more recent Windows SDK?
Simple answer: it will probably take longer to do that on its own that the changes I want to make to the game - and it might not work as intended either, dragging me into a much more frustrating "porting" exercise. Also, if I were to do this sort of work, it is more likely I'd change it over to OpenGL so I could later do a Mac port... (And I'd definitely not move it to DX10 or higher, because it then won't run on XP).
Needless to say, I'm not immediately planning to do any of that ;-)
But I will definitely keep on with the original aims (even if it means beating an old PC into submission first...)
EDIT:
Going to use my retired copy of Windows XP (32-bit) and VS 2008 (probably) on a creaking Pentium 4 system that has no graphics card slot (it has Haiku Alpha 2 on it right now... that at least flies! :-D)
That way, I can frak about with all kinds of rubbish from 4 years ago, without destroying my now-quite-comfy-thank-you work dev environment...
Installing Windows XP after all this time... Wish me luck!
EDIT 2:
Woo! This PC is actually pretty nice for dev, given its age! 2.96GHz Pentium 4, 2GB RAM... Shame about the graphics card... or lack of one.
Also, shame the DVD drive sounds like a f***king F1 car... I tell ye, it's got gear changes and everything!! ... Sounds like Silverstone...
EDIT 3:
Yeah, I think that internal DVD drive is dead.
Bit much when my external USB drive does better than IDE directly (a really, really slow drive I originally bought for my dreadful Samsung Netbook... thing... and then, later used on the MBA until I realised it was quicker to use the remote drive on the iMac...)
EDIT 4:
So! P4 machine running and building Arx :-) Even in Debug, it runs well (including font rendering, oddly) which proves - if such proof be needed - that it is not a slow game in and of itself... Some hunting no doubt required to solve these issues...
EDIT 5:
And in Release, it runs superbly well, even on this awful integrated Intel graphics card! Might as well just play it on this machine instead :-D
But no fear, I will still endeavour to investigate these mysterious issues on more modern machines... Starting tomorrow ;-)
Oh, and in case you're wondering... Yep, magic is now a doddle to cast!
EDIT 6:
D'you know... The issue with casting might actually be as simple as the application not taking account of the Windows mouse speed settings?
Using the Apple Trackpad started me on this line of thought - it was so much easier to cast spells on the game with it... Then I noticed it's tracking speed was not the same as the Intellimouse (same mouse on both the new machine, and the P4 machine)...
So I changed the speed in *Windows* to the half way point, which I think is default...
Suddenly, magic casting worked. Really should have tried that sooner ;-)
So, using the normal Windows application API calls for the mouse might solve this automatically for all machines, if lucky - I will add some code to the game startup to do this tomorrow at some point, and see what it does.
Doesn't solve the font issue, but at least the game is playable now!
Arx Fatalis - Fixup Build Attempt
So, I was poking about in Arx Fatalis on Steam, which I bought ages ago and barely touched**...
Tonight, I fired it up once more - only to find that there are one or two issues that I know I didn't have back in the original release days, on a much, much slower PC:-
Issue one: every time any font appears on the screen, the rendering speed dramatically (and I mean dramatically) slows down.
Issue two: casting spells is practically impossible. I know I found it far, far easier when I owned it before in the time of yore, and so am certain this is some kind of modern hardware incompatibility deep in the glyph-tracing code (searching the net, some people have this issue - most believe it is just players not being accurate enough in the tracing. Trust me, as someone who played this game lots on original release: it isn't that.)
After trying various fiddles to try and resolve these issues, I remembered that the Arx Fatalis source code had been released on the 'net some time ago - so I went and grabbed that instead.
So, just a short(ish) blog post to announce my intention to build my own custom version of this fairly old, but still quite cool RPG, that will fix the font problem and (hopefully) the magic problem.
I might even make some other adjustments too (the UI has some real issues that I truly hate, for example), but this depends how carried away I get...
First obstacle, though, is that the source code relies upon DirectX7 APIs and structs that do not really exist in the latest DirectX SDKs... I'm a bit wary about putting August 2007's SDK on a Windows 7 system that I use mainly for work... but I probably will anyway :-D
Watch this space for more updates - I have to stop now, so I am able to get up in the morning and go to the dentist to have my teeth tortured...
** No, scratch that: here's the full, tedious story... I originally bought it not long after it came out, which was years ago, before Steam even existed. I nearly completed it back then, but various clear-outs of old crap later, and I no longer owned the CD version of the game. Then a bargain sale of Arx Fatalis came up on Steam last year, and I grabbed the game again... then forgot about it until now. Phew. Thanks for your patience...
Monday, 22 August 2011
Ludum Dare "Dummy" attempt
I've never done a restricted time game session before - of any kind.
I'd been thinking of seeing if I could make a game in a weekend for a while, when I noticed (probably from the Twitter feed of Notch - Minecraft's creator) that Ludum Dare 48 hour competition was to take place last weekend.
So... armed with only a distantly fading memory of making 2D platformers on the Amiga... I thought I'd give it a go.
I decided immediately that, having never done anything like this, I would not be officially entering the race (seemed kinda wildly pointless). But I would otherwise stick to their rules, and develop my game alongside everyone else (time-wise).
Tools I would use included XNA 4.0 (never written anything with XNA before this), a little sound app called sfxr, Paint.Net combined with ASESPRITE.
"sfxr" i actually discovered during the weekend, while watching Notch's own LD feed. It's a great little app for making square, sine and sawtooth sound effects, combined with other after-effects applies (stuff that a DSP would give you in hardware, all done in this fab little software tool).
So, what did I achieve?
Well... I made a game. Of sorts ;-)
It is "complete" in the sense that you can play it through from start to finish, and win (you do so by collecting all the coins, which then opens up a special escape room that you can't otherwise access).
It's also pretty dire :-D
In fact, it turned out the most problematic part for me was doing the graphics. Years ago, I was fairly proficient at average quality sprites, but I realised (while doing this LD dummy run) that I used to take *ages* to make those. Trying to get quality out of 48 hours worth on graphics *alone* would probably be unlikely.
You can see this from the game itself:
http://www.youtube.com/watch?v=KWIz_e7Upt8
(Note: terrible updating and weird coin animation are down to the screen capture software... although the animation in the game is nowt to write home about anyway ;-))
So, I finished a (rather crap) game in under 48 hours - and in all honesty, not even focusing on it for most of that time...
So what did I learn from all this?
1. Dedication
As I just mentioned, my focus was not entirely on the project. At all. And on the first night, I even had some wine (which was a terrible mistake! Alcohol and coding do not mix at all well for me...)
Next time around (when I plan to actually enter one of these things), I will put aside the entire weekend - making sure shopping, clothes washing, etc. is all completed - so there is nothing else other than the game.
2. Graphics (specifically pixel art) practise
Boy, do I need this!
Watching people like Notch do this, you can easily see how they achieve their effects, and that can make it seem much easier than it actually is to do this in a short period of time.
Those people have been doing these sorts of events for years. They've picked up skills. I need to hone mine overall, but nowhere more significantly than on the graphics.
(A side remark about this from a friend, in answer to my own knocking of the graphics, was almost enough to demotivate me completely from the project... I did not expect that, but then... I didn't expect to be this crap at it either. So noted for future).
So, before the next competition, I will be practising making sprites. Lots of sprites. Also, rather than just importing individual .png files, I will probably attempt to write several sprite sheet importers, just for the practice of doing it quickly. I lost a fair bit of time adding endless variables to store textures in, simply because I hadn't thought the animation frames through from the start.
3. Random enemies == BAAAD!
I knew from the start that I was going to procedurally generate some of this game, both because I thought it would be easier, but also because the game I had in mind early on was derived from an ancient Dragon 32 game called Android Attack (which itself ripped off Beserk):
http://www.youtube.com/watch?v=hFYXnFkNoZQ
Turns out that in coding (and ultimately gameplay) terms, this was the single worst decision I made.
The added irony is that I could have so easily placed the enemies in the level files, since I made code to load in bitmaps for that! (And then added the coins in that fashion).
I did add some allowance for the player's start position at the beginning of the game, so the enemies would not simply appear on top of him (before that, you could end up in a Jet Set Willy style infinite death loop right from the first moments!)
Even with that, I did not make the game generate the enemies when the player first enters the room (allowing for his initial position), so it was still possible to die on first encountering a room. However, even had I added this, because each room has multiple doorways, and because I stored all enemy positions for each room so they would be in the last place they were when you last entered, it would still be possible to enter from a different door and get trapped.
Proper placement of *designed* enemy starts and paths would have eliminated this pathetic design flaw.
I will only ever make randomly placed enemies in future, if and only if the play area is a large open space (i.e. devoid of close-knit walls and passages).
BIG lesson learned there!!
(To be fair to myself, in all the games I used to make years ago, I never ever made any that relied on random positions of enemies: they always had level designers of some form).
4. XNA is easy peasy... but you still have a learning curve (even if tiny!)
The hit I took for learning XNA as I went was actually pretty small. But I expect this to be almost non-existent in future attempts.
I am, for example, unsure of the best way to load sprite banks, and need to find that out before another game is done. (I was loading all textures individually, although associating them with loops for related stuff - the exception to this being the main character. I need an established pattern for that, but this is my own issue, not XNA's).
Also, I - at the last minute, of course - tried to run the game on the Xbox 360 - only to find that both the resolution was wrong, and also that (even with rez independence) I could not persuade it to offset the top left of the screen correctly.
Little things like this cost valuable time on the project. You could argue that it was possibly made up for by many other things simply being done for you (some function argument discrepancies between floats and ints annoyed me, but I could see why they made the decision - and you don't want endless API overloads for a compact console Made For Idiots game system :-D)
Conclusion
So overall, I think all of this stuff can be addressed with some small game experiments in coming weeks, in my spare time.
Once I have formed regular patterns for 48 hour shots of time, then I am pretty certain I can make decent to very good 2D games, within only a few more attempts.
However...
Notch's game also made me want to try other stuff, like the pseudo 3D Wolfenstein / Dungeon Master type games that he often does. It should be noted, though, that Notch doesn't always succeed at these (his last attempt was a big fail, unlike this one), and he's been doing games like that for years and years...
So, maybe I should try that type of game as a dummy run of its own.
And then of course there are proper 3D games. I know for certain that my inability to model anything would be a HUGE hurdle for those (even outside of 48 hour competitions!) - so I think I will take such things slowly...
(Or just go for really basic, ultra-retro abstract shapes... But that could get wearing very quickly ;-))
My game from this round - just called "Escape!" (this being the theme of this contest) is a success in terms of my completing something recognisable as a game, but an epic failure as anything you'd really want to play out of any kind of choice.
But it has awakened in me a desire to do many many more games... and that was something I thought had long since left me.
This can only be a totally fantastic development :-)
EDIT:
Should you be a mad freak, who wishes to discover all the weaknesses I never mentioned in this article, then here is the game.
You will also need:
http://go.microsoft.com/fwlink/?LinkId=199021
and
http://go.microsoft.com/fwlink/?LinkID=148786
to make it run.
Then just grab this... you sadist :P
http://dl.dropbox.com/u/12219256/escape_thing.zip
(let me know if it fails... seems XNA doesn't want you to try it out...)
I'd been thinking of seeing if I could make a game in a weekend for a while, when I noticed (probably from the Twitter feed of Notch - Minecraft's creator) that Ludum Dare 48 hour competition was to take place last weekend.
So... armed with only a distantly fading memory of making 2D platformers on the Amiga... I thought I'd give it a go.
I decided immediately that, having never done anything like this, I would not be officially entering the race (seemed kinda wildly pointless). But I would otherwise stick to their rules, and develop my game alongside everyone else (time-wise).
Tools I would use included XNA 4.0 (never written anything with XNA before this), a little sound app called sfxr, Paint.Net combined with ASESPRITE.
"sfxr" i actually discovered during the weekend, while watching Notch's own LD feed. It's a great little app for making square, sine and sawtooth sound effects, combined with other after-effects applies (stuff that a DSP would give you in hardware, all done in this fab little software tool).
So, what did I achieve?
Well... I made a game. Of sorts ;-)
It is "complete" in the sense that you can play it through from start to finish, and win (you do so by collecting all the coins, which then opens up a special escape room that you can't otherwise access).
It's also pretty dire :-D
In fact, it turned out the most problematic part for me was doing the graphics. Years ago, I was fairly proficient at average quality sprites, but I realised (while doing this LD dummy run) that I used to take *ages* to make those. Trying to get quality out of 48 hours worth on graphics *alone* would probably be unlikely.
You can see this from the game itself:
http://www.youtube.com/watch?v=KWIz_e7Upt8
(Note: terrible updating and weird coin animation are down to the screen capture software... although the animation in the game is nowt to write home about anyway ;-))
So, I finished a (rather crap) game in under 48 hours - and in all honesty, not even focusing on it for most of that time...
So what did I learn from all this?
1. Dedication
As I just mentioned, my focus was not entirely on the project. At all. And on the first night, I even had some wine (which was a terrible mistake! Alcohol and coding do not mix at all well for me...)
Next time around (when I plan to actually enter one of these things), I will put aside the entire weekend - making sure shopping, clothes washing, etc. is all completed - so there is nothing else other than the game.
2. Graphics (specifically pixel art) practise
Boy, do I need this!
Watching people like Notch do this, you can easily see how they achieve their effects, and that can make it seem much easier than it actually is to do this in a short period of time.
Those people have been doing these sorts of events for years. They've picked up skills. I need to hone mine overall, but nowhere more significantly than on the graphics.
(A side remark about this from a friend, in answer to my own knocking of the graphics, was almost enough to demotivate me completely from the project... I did not expect that, but then... I didn't expect to be this crap at it either. So noted for future).
So, before the next competition, I will be practising making sprites. Lots of sprites. Also, rather than just importing individual .png files, I will probably attempt to write several sprite sheet importers, just for the practice of doing it quickly. I lost a fair bit of time adding endless variables to store textures in, simply because I hadn't thought the animation frames through from the start.
3. Random enemies == BAAAD!
I knew from the start that I was going to procedurally generate some of this game, both because I thought it would be easier, but also because the game I had in mind early on was derived from an ancient Dragon 32 game called Android Attack (which itself ripped off Beserk):
http://www.youtube.com/watch?v=hFYXnFkNoZQ
Turns out that in coding (and ultimately gameplay) terms, this was the single worst decision I made.
The added irony is that I could have so easily placed the enemies in the level files, since I made code to load in bitmaps for that! (And then added the coins in that fashion).
I did add some allowance for the player's start position at the beginning of the game, so the enemies would not simply appear on top of him (before that, you could end up in a Jet Set Willy style infinite death loop right from the first moments!)
Even with that, I did not make the game generate the enemies when the player first enters the room (allowing for his initial position), so it was still possible to die on first encountering a room. However, even had I added this, because each room has multiple doorways, and because I stored all enemy positions for each room so they would be in the last place they were when you last entered, it would still be possible to enter from a different door and get trapped.
Proper placement of *designed* enemy starts and paths would have eliminated this pathetic design flaw.
I will only ever make randomly placed enemies in future, if and only if the play area is a large open space (i.e. devoid of close-knit walls and passages).
BIG lesson learned there!!
(To be fair to myself, in all the games I used to make years ago, I never ever made any that relied on random positions of enemies: they always had level designers of some form).
4. XNA is easy peasy... but you still have a learning curve (even if tiny!)
The hit I took for learning XNA as I went was actually pretty small. But I expect this to be almost non-existent in future attempts.
I am, for example, unsure of the best way to load sprite banks, and need to find that out before another game is done. (I was loading all textures individually, although associating them with loops for related stuff - the exception to this being the main character. I need an established pattern for that, but this is my own issue, not XNA's).
Also, I - at the last minute, of course - tried to run the game on the Xbox 360 - only to find that both the resolution was wrong, and also that (even with rez independence) I could not persuade it to offset the top left of the screen correctly.
Little things like this cost valuable time on the project. You could argue that it was possibly made up for by many other things simply being done for you (some function argument discrepancies between floats and ints annoyed me, but I could see why they made the decision - and you don't want endless API overloads for a compact console Made For Idiots game system :-D)
Conclusion
So overall, I think all of this stuff can be addressed with some small game experiments in coming weeks, in my spare time.
Once I have formed regular patterns for 48 hour shots of time, then I am pretty certain I can make decent to very good 2D games, within only a few more attempts.
However...
Notch's game also made me want to try other stuff, like the pseudo 3D Wolfenstein / Dungeon Master type games that he often does. It should be noted, though, that Notch doesn't always succeed at these (his last attempt was a big fail, unlike this one), and he's been doing games like that for years and years...
So, maybe I should try that type of game as a dummy run of its own.
And then of course there are proper 3D games. I know for certain that my inability to model anything would be a HUGE hurdle for those (even outside of 48 hour competitions!) - so I think I will take such things slowly...
(Or just go for really basic, ultra-retro abstract shapes... But that could get wearing very quickly ;-))
My game from this round - just called "Escape!" (this being the theme of this contest) is a success in terms of my completing something recognisable as a game, but an epic failure as anything you'd really want to play out of any kind of choice.
But it has awakened in me a desire to do many many more games... and that was something I thought had long since left me.
This can only be a totally fantastic development :-)
EDIT:
Should you be a mad freak, who wishes to discover all the weaknesses I never mentioned in this article, then here is the game.
You will also need:
http://go.microsoft.com/fwlink/?LinkId=199021
and
http://go.microsoft.com/fwlink/?LinkID=148786
to make it run.
Then just grab this... you sadist :P
http://dl.dropbox.com/u/12219256/escape_thing.zip
(let me know if it fails... seems XNA doesn't want you to try it out...)
Friday, 29 July 2011
Matthew Smith has left the building
The Original Plan: Do as Manic Miner...
The sprite routines (and general screen updating code) was going to be awesome.
I was going to copy the great Spectrum coding legend, Matthew Smith, and write directly to the Speccy's screen memory every frame, 50 frames a second, using interrupts.
You have around 14000 T-states (CPU cycles, roughly) to play with at the start if the interrupt routine, before the first byte of screen data is drawn. Surely this would be plenty to be getting on with? I'd have my sprites drawn, edge tiles drawn, scrolling done, music playing - the works. And I'd always be ahead of the vertical image trace. Yeahmon!
Except... and it breaks my heart to realize this... but, basically, the Spectrum... the thing about the Spectrum... the one thing you really need to know about the Spectrum is...
The Spectrum SUCKS.
Okay. It's an old machine (to say the least - that was after all the point of the exercise) - but I have discovered in my experiments that even a straight screen wipe - yes, a start-at-beginning-move-to-end-of-framebuffer screen wipe, is IMPOSSIBLE** in the time you have without the beam catching up.
Yes, I even tried moving to the second 32k of memory (uninterrupted by the ULA), for screen wiping, and for sprites. True, I could probably just about optimise the screen wipe to work... But even if so, I wouldn't be able to do anything else at all in that frame.
So, how did Matthew Smith do it?
Well, first of all, he would never have cleared the screen at all - except when the level was first drawn. He'd have written directly into screen memory, XORing data as he went (you can see this when Miner Willy walks past the scenery, in fact).
Additionally, and crucially, he most likely worked out all the line-based operations in advance, and then - instead of rendering one sprite at a time - drew individual vertical lines that shared Y coordinates between sprites, and did so in order.
This is fine, and I had planned to rewrite my sprite routines to do this (even if it's fiddly, it would almost certainly let me render approximately eight sprites smoothly).
Except I realised I wasn't simply trying to rewrite Manic Miner or Jet Set Willy: games with largely blank backgrounds, that draw most of each room in one pass and then leave it alone, and with only handfuls of sprites to worry about.
I want to make games that scroll, have fancy effects, maybe have massive boss sprites, etc.
I conceded at this point: there is no way to do all that at 50 frames a second on a Spectrum, no matter how well you optimise (well, unless you do some pretty specific cheats... which will hardly work for a variety of games as I describe).
So, I have grudgingly decided that for my project to go ahead, I will have to use... double buffering.
Double Buffering: Man's best friend... right?
Now of course there will be some of you now screaming at the screen: "Of COURSE you should double buffer, you moron! Why didn't you do that in the first place?"
Now hold on, and re-read the first part of this article. It is IMPOSSIBLE to do even a simple screen wipe in a single frame.
A screen wipe is considerably simpler and faster than copying a damn buffer into the frame memory.
That was why: I wanted 50 frames a second gameplay. Sadly, for my purposes, this is not to be.
There is another consideration for double buffering: memory. We are working with 48K of RAM, and not all of that is available (the screen itself takes up around 7K of it, and then we have the stack at the top of memory, the interrupt vector, our at-the-moment very simple code, sprite data, etc.)
Add to this that only the top 32K is uncontended with the CPU (and therefore runs without halting interruptions from the ULA chip). We would ideally want our buffer here, but of course we'd also want all our intensive calculation code here, too.
So, there are many reasons I would like to avoid double buffering on the no-hardware Spectrum. But there are a few advantages, too...
Advantage One: I can draw into a linear buffer!
Yes indeed, I can determine my buffer to be in whatever form I like. If I was crazy (and I really would have to be), I could create a chunky bitmap buffer with colours per pixel! I wouldn't be able to display all those colours, but hey, maybe I could fake it..?
Of course, reality crashes into our fantasy world once again: there are limits to what you can do speed-wise. But in fact, having a linear buffer (with a cached 192 line framebuffer ptr array) would in fact make things easier for timings with the beam. So win!
However...
14000 T states (slightly more, but not much). We have to get the bulk done here in the first part of the interrupt routine. Then the beam will actually be drawing the pixels and colours, and it will be a race to get done before the beam catches us up.
In fact, this situation is worse than I've described. We won't get all of those 14000 T states (or even each lines worth of 224 T states), because some of the cycles will be lost to interruptions by the ULA (it takes precedence over the CPU, locking it out).
So, quite simply we will have to accept that, for all the reasons given, the very best framerate we can hope for with double buffering is 25 fps. (Or 30 fps on US models).
Double poo sandwhich :-(
The Upside
The big win of all this, though, is that all kinds of game styles can emerge from it. Our platformers (the original game style choice for this project) can have much more detailed backdrops if we want (and balance for framerate). We can do scrolling shooters, Gauntlet-style multi-directional games, pseudo-3D stuff like Dungeon Master (well, an imitation), and even perhaps proper wireframe - or even Freescape-style filled! - 3D graphics.
Having said all of that, I'm still grumpy. I wanted to prove myself a God of the Matthew Smith order, and then some. But I know that without severely limiting what I can do in terms of game design, I just can't do that.
It does, however, make me even more awestruck by that strange, drug-addled genius that gave the world its first proper ZX Spectrum arcade game that didn't suck: Manic Miner.
Matthew Smith, I salute you!
Footnote:
Some people might quite rightly point out that you don't need to in fact wipe or update the entire screen each frame. This is true (and very few games on the Spectrum even come close to doing so). But even given that, the limitations on what you can have where on the screen in order to have no flickering at 50 frames a second is just far too restrictive for what I want to do. Boo, Spectrum. But also... *hugs*
** I'd love someone to prove me wrong here, but I tried every imaginable optmisation. The screen wipe was tried with both the LDIR method, and a single XOR A followed by a LD (HL), A loop. It no workey :-( Well, not in a single frame, anyway.
EDIT: I think this may be the answer! So, Project Spectrum may well be back on!
http://zxspectrumdev.blogspot.co.uk/
More about it here:
http://www.worldofspectrum.org/forums/showthread.php?t=24788
So psyched - my original aim is now back within realistic bounds... A proper flicker-free game!
The sprite routines (and general screen updating code) was going to be awesome.
I was going to copy the great Spectrum coding legend, Matthew Smith, and write directly to the Speccy's screen memory every frame, 50 frames a second, using interrupts.
You have around 14000 T-states (CPU cycles, roughly) to play with at the start if the interrupt routine, before the first byte of screen data is drawn. Surely this would be plenty to be getting on with? I'd have my sprites drawn, edge tiles drawn, scrolling done, music playing - the works. And I'd always be ahead of the vertical image trace. Yeahmon!
Except... and it breaks my heart to realize this... but, basically, the Spectrum... the thing about the Spectrum... the one thing you really need to know about the Spectrum is...
The Spectrum SUCKS.
Okay. It's an old machine (to say the least - that was after all the point of the exercise) - but I have discovered in my experiments that even a straight screen wipe - yes, a start-at-beginning-move-to-end-of-framebuffer screen wipe, is IMPOSSIBLE** in the time you have without the beam catching up.
Yes, I even tried moving to the second 32k of memory (uninterrupted by the ULA), for screen wiping, and for sprites. True, I could probably just about optimise the screen wipe to work... But even if so, I wouldn't be able to do anything else at all in that frame.
So, how did Matthew Smith do it?
Well, first of all, he would never have cleared the screen at all - except when the level was first drawn. He'd have written directly into screen memory, XORing data as he went (you can see this when Miner Willy walks past the scenery, in fact).
Additionally, and crucially, he most likely worked out all the line-based operations in advance, and then - instead of rendering one sprite at a time - drew individual vertical lines that shared Y coordinates between sprites, and did so in order.
This is fine, and I had planned to rewrite my sprite routines to do this (even if it's fiddly, it would almost certainly let me render approximately eight sprites smoothly).
Except I realised I wasn't simply trying to rewrite Manic Miner or Jet Set Willy: games with largely blank backgrounds, that draw most of each room in one pass and then leave it alone, and with only handfuls of sprites to worry about.
I want to make games that scroll, have fancy effects, maybe have massive boss sprites, etc.
I conceded at this point: there is no way to do all that at 50 frames a second on a Spectrum, no matter how well you optimise (well, unless you do some pretty specific cheats... which will hardly work for a variety of games as I describe).
So, I have grudgingly decided that for my project to go ahead, I will have to use... double buffering.
Double Buffering: Man's best friend... right?
Now of course there will be some of you now screaming at the screen: "Of COURSE you should double buffer, you moron! Why didn't you do that in the first place?"
Now hold on, and re-read the first part of this article. It is IMPOSSIBLE to do even a simple screen wipe in a single frame.
A screen wipe is considerably simpler and faster than copying a damn buffer into the frame memory.
That was why: I wanted 50 frames a second gameplay. Sadly, for my purposes, this is not to be.
There is another consideration for double buffering: memory. We are working with 48K of RAM, and not all of that is available (the screen itself takes up around 7K of it, and then we have the stack at the top of memory, the interrupt vector, our at-the-moment very simple code, sprite data, etc.)
Add to this that only the top 32K is uncontended with the CPU (and therefore runs without halting interruptions from the ULA chip). We would ideally want our buffer here, but of course we'd also want all our intensive calculation code here, too.
So, there are many reasons I would like to avoid double buffering on the no-hardware Spectrum. But there are a few advantages, too...
Advantage One: I can draw into a linear buffer!
Yes indeed, I can determine my buffer to be in whatever form I like. If I was crazy (and I really would have to be), I could create a chunky bitmap buffer with colours per pixel! I wouldn't be able to display all those colours, but hey, maybe I could fake it..?
Of course, reality crashes into our fantasy world once again: there are limits to what you can do speed-wise. But in fact, having a linear buffer (with a cached 192 line framebuffer ptr array) would in fact make things easier for timings with the beam. So win!
However...
14000 T states (slightly more, but not much). We have to get the bulk done here in the first part of the interrupt routine. Then the beam will actually be drawing the pixels and colours, and it will be a race to get done before the beam catches us up.
In fact, this situation is worse than I've described. We won't get all of those 14000 T states (or even each lines worth of 224 T states), because some of the cycles will be lost to interruptions by the ULA (it takes precedence over the CPU, locking it out).
So, quite simply we will have to accept that, for all the reasons given, the very best framerate we can hope for with double buffering is 25 fps. (Or 30 fps on US models).
Double poo sandwhich :-(
The Upside
The big win of all this, though, is that all kinds of game styles can emerge from it. Our platformers (the original game style choice for this project) can have much more detailed backdrops if we want (and balance for framerate). We can do scrolling shooters, Gauntlet-style multi-directional games, pseudo-3D stuff like Dungeon Master (well, an imitation), and even perhaps proper wireframe - or even Freescape-style filled! - 3D graphics.
Having said all of that, I'm still grumpy. I wanted to prove myself a God of the Matthew Smith order, and then some. But I know that without severely limiting what I can do in terms of game design, I just can't do that.
It does, however, make me even more awestruck by that strange, drug-addled genius that gave the world its first proper ZX Spectrum arcade game that didn't suck: Manic Miner.
Matthew Smith, I salute you!
Footnote:
Some people might quite rightly point out that you don't need to in fact wipe or update the entire screen each frame. This is true (and very few games on the Spectrum even come close to doing so). But even given that, the limitations on what you can have where on the screen in order to have no flickering at 50 frames a second is just far too restrictive for what I want to do. Boo, Spectrum. But also... *hugs*
** I'd love someone to prove me wrong here, but I tried every imaginable optmisation. The screen wipe was tried with both the LDIR method, and a single XOR A followed by a LD (HL), A loop. It no workey :-( Well, not in a single frame, anyway.
EDIT: I think this may be the answer! So, Project Spectrum may well be back on!
http://zxspectrumdev.blogspot.co.uk/
More about it here:
http://www.worldofspectrum.org/forums/showthread.php?t=24788
So psyched - my original aim is now back within realistic bounds... A proper flicker-free game!
Sunday, 24 July 2011
ZX Spectrum - Screen memory layout
The Sinclair 48K Spectrum was just about the cheapest home computer you could buy in 1982 that had colour graphics.
There was a reason...
Just about every corner was cut in producing the ZX Spectrum: it had no custom hardware of any kind, short of a very simple ULA chip that did as little as it could get away with in order to have a working computer system, and the 16K ROM chip, with BASIC in it.
One consequence of this cost-cutting exercise was the strange, non-linear screen memory layout...
The Spectrum provided 256 pixels along the x-axis, and 192 lines along the y-axis.
Each byte in screen memory contained eight pixels, with no colour information. The colour was set in the attributes, a sequence of single bytes that were placed in memory immediately after the pixel information, and which specified the foreground and background colours for each 8x8 pixel cell.
Though the attributes are placed linearly, the pixels themselves are not. You can see this quite clearly when Spectrum games load their title screens:
The loader here is simply reading all the bytes from $4000 (16384) to the end of screen RAM at $5AFF, in order. As you can see, the pixels are arranged in a very "interesting" fashion...
This makes accessing screen memory a little bit more involved than simply adding Y lots of TotalXBytes to find the line.
Finding screen line addresses from a Y Coordinate
Given a Y coordinate stored in an 8-bit register:
Y Coordinate bit layout (MSB to LSB):
zzxx xnnn
we can produce a 16-bit address in a register pair by placing these bits as follows:
Register pair bit layout (R are the bits for the x-axis offset, 010 provides the base address $4000):
010z znnn xxxR RRRR
Who knows why on earth the engineers designing the Spectrum decided to swap the position of the nnn and xxx bits... but they did.
(I'm sure it was the same kind of reasoning as providing a console with half an altivec unit... ahem.)
Geek Moment - Some code to use this stuff
Here is some Z80 code that makes use of this knowledge, to clear the screen - not in the order as shown in the loader above, but sequentially (from the user's point of view).
This code ignores the attribute memory for convenience's sake (that is linear, and would be a straight blat anyway... though it might be nice to do it in sync with each group of 8 lines... ;-))
There was a reason...
Just about every corner was cut in producing the ZX Spectrum: it had no custom hardware of any kind, short of a very simple ULA chip that did as little as it could get away with in order to have a working computer system, and the 16K ROM chip, with BASIC in it.
One consequence of this cost-cutting exercise was the strange, non-linear screen memory layout...
The Spectrum provided 256 pixels along the x-axis, and 192 lines along the y-axis.
Each byte in screen memory contained eight pixels, with no colour information. The colour was set in the attributes, a sequence of single bytes that were placed in memory immediately after the pixel information, and which specified the foreground and background colours for each 8x8 pixel cell.
Though the attributes are placed linearly, the pixels themselves are not. You can see this quite clearly when Spectrum games load their title screens:
The loader here is simply reading all the bytes from $4000 (16384) to the end of screen RAM at $5AFF, in order. As you can see, the pixels are arranged in a very "interesting" fashion...
This makes accessing screen memory a little bit more involved than simply adding Y lots of TotalXBytes to find the line.
Finding screen line addresses from a Y Coordinate
Given a Y coordinate stored in an 8-bit register:
Y Coordinate bit layout (MSB to LSB):
zzxx xnnn
we can produce a 16-bit address in a register pair by placing these bits as follows:
Register pair bit layout (R are the bits for the x-axis offset, 010 provides the base address $4000):
010z znnn xxxR RRRR
Who knows why on earth the engineers designing the Spectrum decided to swap the position of the nnn and xxx bits... but they did.
(I'm sure it was the same kind of reasoning as providing a console with half an altivec unit... ahem.)
Geek Moment - Some code to use this stuff
Here is some Z80 code that makes use of this knowledge, to clear the screen - not in the order as shown in the loader above, but sequentially (from the user's point of view).
; Clear the screen in an ordered, top to bottom fashion
;
; Entry: None
; Exit: A, BC, D, HL all trashed
; (push on stack if needed)
; (push on stack if needed)
;
; Notes:
;
; This is obviously slower than simply blatting from
; $4000 to $5800, but that would reveal the three sectors
; of the screen AND the alternate line pattern
; (both seen when loading screens)
; (both seen when loading screens)
; This is an example method to show how to address screen
; RAM using a Y coordinate instead, so we can move from
; top to bottom, line by line.
; RAM using a Y coordinate instead, so we can move from
; top to bottom, line by line.
;
clearscreen_ordered:
LD B,192 ; num y lines
XOR A ; clear the accumulator
; (MUCH faster than LD A,$00)
; (MUCH faster than LD A,$00)
LD C,A ; c == y coord
; Here, we create the screen line pointer in HL,
; based upon the given y-coordinate in C.
; based upon the given y-coordinate in C.
; The y coordinate needs to be shuffled about a bit to be
; in the correct format for the Spectrum's bizarre
; hardware.
; in the correct format for the Spectrum's bizarre
; hardware.
ylinesloop:
LD A,C
AND $7 ; get first three bits,
; in the same position in H
; in the same position in H
LD H,A
LD A,C
AND $38 ; next three bits need to be
; shifted left twice,
; and placed in L
; shifted left twice,
; and placed in L
RLA
RLA
LD L,A
LD A,C
AND $C0 ; last two bits need to be
; shifted right three times,
; and placed in H
; shifted right three times,
; and placed in H
RRA
RRA
RRA
OR H
OR $40 ; also include the base address
; (screen mem starts at $4000)
; (screen mem starts at $4000)
LD H,A ; HL = ptr to line
; Individual lines are thankfully arranged in a linear
; fashion in memory. We can simply increase the
; pointer by one each time to clear a single line.
; fashion in memory. We can simply increase the
; pointer by one each time to clear a single line.
LD D,32 ; bytes per line (256 pixels)
xbytesloop:
LD (HL),$00 ; all pixels cleared
INC HL
DEC D
JP NZ,xbytesloop
INC C
DEC B
JP NZ,ylinesloop
ret
This code ignores the attribute memory for convenience's sake (that is linear, and would be a straight blat anyway... though it might be nice to do it in sync with each group of 8 lines... ;-))
ZX Spectrum Platformer Project - Misson Statement
Still coming up with that... but here is an overview of what I intend to cover!!
BASIC vs Machine Code
- Show simple screen wipe in BASIC
- Show simple screen wipe in assembly
- Explain screen mem insanity
- Show ordered screen wipe
- Show function to calc location y line in HL, x byte and rotation for x coord
- Show Sprite copying routine
- Interrupts - and why they don't suck
- Tiled level drawing
- Collision between non-evil platforms and enemies & Evil Platforms
- Random discussion on horizontal scrolling (and why vertical sucks by comparison)
- Sound synth (two channel!) for 1-bit beeper shit (no, I repeat NO 128K 8912 chip)
Game
- Keyboard!
- Joystick!! (as if modern Speccy users care… um, fuck the oxymoron there)
- C# Spectrum graphic editor (by me!)
- Level designing
- Pulling it all together (for a 1-level proper mad game!!)
Future ideas:
- Scrolling shoot-em-up?
- DEFINITELY: C64 platformer, maybe ShootEmUp - because… I never did!! XD
- Atari ST - next? (for same reason as C64)
Argument:
I see this project's purpose as two-fold:
- Show people how gameplay always triumphs, even with IMMENSELY limited resources
- Give back Da Respekt to the hardware, dudes!!! You can't get any crapper than the Spectrum for this, yet it was the platform of CHOICE for gameplay in its day (even though the C64 was far superior in terms of hardware, etc.)- how was this done?
But there's also:
- Something is wrong with the games industry… (oh this could go on for a bit, but… rather than be a bore, I thought showing WHY via the game would be the best way)
Subscribe to:
Posts (Atom)