Z80 Gamedev for CPC, Enterprise and MSX –  Coding a multiplatform 8 bit game in assembly

Z80 Gamedev for CPC, Enterprise and MSX – Coding a multiplatform 8 bit game in assembly

Hello! My name’s Keith, I’m the author of
the Chibi Akuma’s 8-bit term bullet hell game and I’m going to be talking you
through some of the code today, and I’ll be explaining how it works!
so firstly let me just describe the game a little bit… hopefully some of you have
seen it but, whether you have or not the game was originally an Amstrad CPC game,
and here’s a video of the CPC version running… but I’m now porting the game to
the ZX Spectrum and also the MSX – now these are all 8-bit z80 based systems
and the game is programmed in assembly, and the reason I’m hoping it might be a
bit interesting for you today is that the code that runs on these systems is
actually the same piece of code with different branches for the different
systems… it’s one piece of code that runs on three systems… not three
different versions of similar code! so what I’m going to be doing is I’m going
to be looking through some of the main core functions of the the code itself
that does the main game engine, and I’m going to be describing how that code
differs depending on the three different systems… and some of the technical
challenges of those developing for those three different systems!
I’m hoping this may be of interest to people who are interested in assembly
coding… are doing basic assembly coding and looking to sort of make something a
bit more advanced, or maybe have done some very advanced coding in one of
these systems but is curious in seeing what the other two systems are like to
develop for… The final group would be people who aren’t really interested in
coding at all, but would just like to hear a bit of what it’s like it to
actually work on these machines! what programming for them is actually
like! So let’s get rid of these little videos because I’m sure there building up the bandwidth good nicely! and let’s get the actual source code into screen
here… so here’s my assembler I use WinAPE for my assembler for all
the systems… I’m going to be discussing this CoreDefs.asm file today… which, it’s
actually not particularly assembly code as such… it’s actually the
definitions that point to what’s called the “jump block”… which is a
set of predefined entry points to the code… now the “CORE” itself is sort of big
and complex, and splits into lots and lots of separate files… and I can’t
do it justice in a short description so I’m going to go through those in small
sections later… but today we’re just going to go through it at a very
basic level… I’ll describe what each of the functions does, and if there were
differences between the different systems (the spectrum the Amstrad
CPC in the MSX)… I will try and describe them to you, and hopefully through that
you’ll get a bit of an idea of how I’ve designed structurally the code
of the Chibi Akumas game and the decisions I’ve had to make when I
took on the Amstrad CPC, the MSX and the ZX Spectrum versions… now it should be
noted to you that while I’ve been programming and I’ve been using the
Amstrad CPC for a great many years, this was my first assembly game, and it was the first time I’d seriously programmed assembly more than just simple type ins…
it’s also the first time I’ve used a Spectrum or a MSX in truth… I really
never used any of those systems in any way… apart from with the spectrum – I
played the games very occasionally when I was very young but I never owned one
until six months ago, I bought the ZX spectrum for this project…
the MSX I started looking at about twelve months ago, so I’m very new to those
systems… and hopefully that will give me an opportunity to explain the things
that I’ve had to learn… the things I’ve come across… and the things that have
surprised me, because if you’ve never used those systems; if you’ve never
programmed for those systems… I’m sure it will surprise you as well! and so maybe
you can learn from my mistakes, my challenges! and maybe you can look at the
conclusions and solutions I found and think “hey that’s a good idea maybe
I’ll do that” or” no I’m sure I can do that better… I’ll do something different” Great! go ahead! we all need to learn from everyone else, so anyway as I say
you’ll see no real code here… you’re just going to see sort of top-level
descriptions of functions, and so we’ll go through that… if you want to hear more
later… reply in the comments to this, tell me what you want to hear about, follow me on patreon… I’m trying to post every week make a new text file
describing in detail one of the functions… just chat to me on Twitter
whatever you want just let me know what people are interested in hearing about,
so anyway let’s make a start, and let’s stop talking! so I’ve mentioned in one of
my previous posts… I use these core definitions called “BuildCPC”, “BuildMSX”
and “BuildZXS”… now this possibly self-explanatory… only
one is enabled at a time, depending on what binary file I want to end up with…
it’s not the same binary running on all three machines… that would be very very
tricky to do! So it’s one piece of source code, different branches enable
and disable depending on which system you actually need to compile for… so as I
say the first part is the CPC part… now the Amstrad CPC has a 320 pixel wide
screen… where’s the spectrum and the MSX only have a 256 pixel wide screen,
so some parts of the code have to move objects around and of course the screen
drawing routine has to draw different amounts for the ZX Spectrum (and msx)… so the CPC has a 320 definition here as a test you can actually disable it and it will it
will actually but build a version of the game that runs on the Amstrad CPC… 256
pixels wide but I don’t actually use it… that was just in the very early days of
getting the code working for 256 pixels… it’s not something I’m actually planning
to do at this stag,e so these in theory you can disable support for the 64K
the 128K and the PLUS machines… I never do that anymore, it was
something I did in the early days when I was concerned I might run out of memory.
The core itself – I should explain – has to fit within a 16K block on all the
machines… there’s a couple of reasons for that, but the main one being – on the
Amstrad CPC 464, I only have 32K of memory in total for everything
so 16k was all I could allocate and in fact that 16K is the core code, the
music files and also the data which makes up the objects in the game, of the
bullets in the game and everything else so 16K is the upper limit…
really the CORE is about 10 to 12K so memory is often a big limitation for all
of these systems but for different reasons, which is curious! I will go into
detail on that in a moment So some macro definitions… these create a
kind of shortcut, which it’s converted to code by the assembler I’ll explain what
this is for… the these were all actually for the ZX Spectrum… on the ZX
spectrum, the interrupt handler is is what’s called into Interrupt Mode 2 (IM2) which I won’t explain it in detail, you don’t really need to know at this stage… but it
uses the register I which is a sort of rare register… now on the MSX and the
CPC the register I isn’t used… so I was actually using it as a spare
variable… but of course that does not work on the ZX spectrum,
because I need it! so I’ve come up with this kind of thing where I keep using I
as a register on the Amstrad and the MSX, and I replace that code with an
alternative for the spectrum and you can see these EXX’s as well… whenever I
want to use the shadow registers on the Amstrad CPC I need to disable interrupts
because my interrupt handler uses the shadow registers… because the ZX Spectrum
interrupt handler – if you did that… I should back talk a little bit… if you
disable interrupts on the Amstrad CPC or the MSX, when you re-enable them the
interrupts will immediately fire… on the ZX Spectrum a missed interrupt is gone…
it’s gone forever… you never get it back! so the the shadow registers aren’t
protected by my interrupt handler on the MSX and the
and the Amstrad CPC, because in most cases I don’t use them… so when I do want
to use them I disable interrupts. On the ZX Spectrum they are protected,
all the registers are protected and so the only time I disable interrupts on the ZX spectrum is when I’m misusing the stack pointer, which unfortunately
I do quite a lot. so I still have problems with missed interrupts… but,this is a way that I’ve come up with so far, to try and reduce the number
of missed interrupts, so these macro definitions here basically allow
me to keep the code the same for the MSX and the Amstrad CPC which is hopefully the fastest way I can do it, and then to make some
compromises… uses a little bit more memory, maybe a little bit slower on the ZXSpectrum, but gets around the limitations of the spectrum.
Something I will point out later, so I might as well mentioned now… A big factor
of the ZX spectrum is its Screen Memory… It only uses about 8 k of Screen memory,
whereas the Amstrad CPC use is about 16K So by definition the ZX
Dpectrum version is actually a lot faster than the Amstrad, just because
it’s pushing half the data around… so all of these compromises in place that make
the spectrum version slower… it’s still actually faster, which is quite handy for
me… because as I say, if they both have a 16 K screen, The spectrum would be
a lot slower, because of various limitations in the way it works with
this memory… so anyway let’s continue from there… now I have a stack pointer
of redefinition here… I move the stack pointer…I don’t use the system default
one, because I never return back to the system… so to keep everything in control
I have a predefined stack pointer… I know where the stack starts… I reset it
whenever I know I’m never going back again. and then here’s this CORE_Start
variable… all of the the code objects and the large data objects
within the the game engine are moveable… I’ve had to move the many many times as
I’ve redesigned the game engine, and so and also in different places on all the
different systems. so you can see here there’s definitions for the core and
what’s called the “bootstrap”… the game variables are what I mentioned earlier
the bullets, the object… things like that… nothing particularly exciting,
but they need to be somewhere where the game engine can always get to them…they need to be in a
constant place, and as it says it needs a few kilobytes there… so they are in place…
and some stuff related to Plus sprites I’m not going to discuss that… not
very interesting to be honest! positions of music files… there’s allocation for two music files, because the boss music changes in the second game, and sound
effects location … again these can move. the level data which is it’s sort of
defined in my specification, if you will, of the game engine that there is 16K
allocated to the game level… now the level can do with it whatever it wants…
it could only use half that, it could have 15k of sprites and 1k of data…
it could have 15k of data, 1K of sprites… it could have 4 K of data 4k of
sprites and 8k of music… it really doesn’t care… the point is the
system has allocated that much resource to the levels, for the level to do
whatever it wants… so the main one is sprites and code and then there are
potentially three other banks of just sprites this was this this was designed
by me to work around the 64k limitation … I wanted to support the
Amstrad CPC 464… it’s only got 32K of ram that’s virtually nothing to do
anything good with, so what I decided to do is split the sprites into four… on the
64K systems, you’d only have one bank of spites on the 128 K systems you’d have up
to four… so you have four times the animation (better sprites, better graphics)
but the basic users still get their game… everyones happy… so that’s what
that’s for… and these definitions are the locations and also the bank
numbers… I am going to go over what bank numbers on the diverse systems
mean later, so just bear with me a moment. so some compiled sprites… these are full
screen images, that are compressed into memory they’re just given a number, it’s
just the loading screens… insert disk image… that kind of thing.
and a bitmap font. now on a couple of the systems I use a bitmap font, which is a
font I’ve designed and put in memory… that’s the 128 K in 464… the msx2 they
use the bitmap font… the ZX Spectrum uses the built-in font on the system (Update:ZX also uses bitmap font now)
and also the cpc464 uses the internal font using internal font is a bit slower, because I
have to move around the memory and especially with the half width font, I
have to alter them I have to alter the in memory data to make it work on screen
and I have to do that on the 464 again it was simply a case
there wasn’t really any choice the font is about three kilobytes in
size… on the 464 there is 32 kilobytes… It wasn’t an option…the ZX Spectrum…
I’m only supporting 128K systems… however the the spectrum has a
problem with regards to its memory layout which makes writing sprite data to the screen problematic…. so it was actually preferable to me to use the
internal font even though in a lot of ways I would have preferred to use the
bitmap one… (Update: Final game uses bitmap font!!!)
I will explain that problem later I do have a chart prepared which
will hopefully make it clear to you how the memory works…
so anyway let’s carry on… so Raster-Colors… the CPC version runs on a 4 color screen and i alternate the colors while the
screen is redrawing to make it look like around 10 to 12 colors and
there is an array of pointers, which says when the color changes need to occur
what the new colors are, and that’s a command that only appears on the CPC
version… because I only do that on the CPC version… there’s a bank copy command
which copies between memory banks and we will go over that later, and a new
comman…d and now this is what’s called a “vector away” which is… it’s a two
byte address lookup, and what I do is I pass it a variable… it looks it up in the
vector array and calls it. I’ve only started adding these
very recently… and the reason is the jump block is getting huge…. in the
jump block you need three bytes per command… the vector array only
needs two, so I’m hoping to save a byte per command, as the job block is getting
bigger and bigger as the game engine is getting more and
more advanced… so I’m planning that when the next version of the game core comes out
that the jump-block will probably be about half the size, and the vector-array will
have taken over a lot of the roles just to try and keep the size as small as I
can… but that’s that’s future plans for next year !
it’s not going to happen with the multi-platform version and it’s not
going to happen with the multi-platform version of Episode two (Update: there are no plans for a multiplatform EP2… sorry!)
because as long as it’s not broke… I’m not going to fix it as long as it keeps working I’m going to
keep it keep it the way it is… so that’s all the Amstrad version, and here we come
to the MSX version much of it’s very much the same… this is worth noting…
you’ll notice we have a y-coordinate for all of our sprites and also for
our font… we have Y co-ordinates for everythinh and that is again relating to the odd way (the odd way compared to the other systems)
that the MSX works with it’s graphics again I’ve got that too in my chart, and we’ll
go into that in some detail… I’ve even got an emulator set up
which will show you exactly how the screen works on the MSX because
the CPC and Spectrum people might be quite surprised by it, so let’s have a look at
that later… so here we have some commands relating
to these mystery y-coordinates which I will go into again we also have a
parallax command which is to do with the backgrounds for the the v9990
graphics accelerator…. you might notice later on… on the
Amstrad version a lot of the background drawing commands are in the level code
and on the MSX & spectrum version they’re in the core itself…. the reason
for that is the 64 K support…. there was no space left in the core… I had
to chop them off into the larger level area… and some of the levels
don’t need backgrounds… so why put it in the core if it’s only used a few times?…
keep it in the level data if everything needs it…. if it’s got to be in a very
reliable place, and very accessible then put it in the core…. that’s that’s why those
are there… and the particle array is a v9990 special effect… when you kill an
enemy it explodes into a shower of stars that sort of fly down the screen…
it was really me messing around and trying to use up all of the extra power
of the new graphics accelerator without completely redesigning the game
in the process so that’s a bit of a special effect, but none of the other
systems can do it because it’s a total misuse of graphical power! that’s
what that does so there we go and here we’ve got some
more commands VDP command number… that’s another vector array for doing special graphics commands… sometimes I need to do those on the MSX… on the spectrum or the CPC I can just access the screen
memory whenever I want but on the MSX you have to use VDP commands so that’s
that! The MSX is a 16 color system in the capacity I’m using it… so I need to be
able to set the palette is required so that’s what this Palette command does and
RleProcessFromMemory is a special command I’ve written and I use
I’ve wrote my own RLE compression format which reduces the file size of
bitmaps… I can stream them straight off disks… but in some cases it’s easier for
me to actually read them out of the system memory so that’s what that
command does… and then the tiles command that is relating to the backgrounds
again… the backgrounds in chibi Akuma’s tend to be solid fill which is just one
color…. gradients which you know change from one color to another smoothly and
they also scroll, and then tile strips now a Tile Strip is a repeating bitmap
on the on the Amstrad CPC because it’s a two bit per pixel system I have 32
pixel wide Tile Maps because of the stack pointer trick I’m using
that is the limit there. on the spectrum because it’s an… so I’m getting these wrong way around the the
Amstrad CPC is a two-bit per pixel system and the spectrum is a 1 bit per
pixel system… the spectrum is just black and white… so it
has the tiles are twice the width they’re 64 pixels wide… the MSX it that’s
actually a sort of 4 bit per pixel system at 16 colors
it actually works quite differently with the tiles though… programmatically it works very differently, but the way they appear on the screen is the same
the tiles aren’t 16 pixels wide they’re actually the full
width of the screen! because I can’t use stack pointers in
that case (to fill the screen), The performance was actually better the bigger (the tile) you used
rather than the other systems, where it was better the smaller you used… that’s another obscurity there! so here we’re on to the spectrum
version… and you’ll see that the LDIA and LDAI macros are now actually using
memory pointers not the I register and then here you’ll notice
these do nothing now, because I don’t disabled and enable interrupts when I’m using the shadow registers because I don’t need to… The
the interrupt handler on the spectrum actually protects them (the one I’ve
written)… the reason I didn’t do that on the Amstrad CPC… there’s a good
reason for it… the spectrum interrupt handler and the MSX interrupt handler run once per screen… The Amstrad CPC one one runs six times per screen and I
need it – because it’s the interrupt handler which is changing the colors mid
screen, which allows me to get more than four colors on the Amstrad CPC screen!
so not disabling interrupts and protecting the registers it’s a bit of a
slowdown on the spectrum, but it would have been a lot more of a slowdown on the
Amstrad CPC so that’s that… and then all of these are pretty much the same as on
the Amstrad, so I will just skip over them… so another memory copying command here a command to set the background
colors of the spectrum … now the spectrum as I said it’s one bit per pixel… so
that’s just black and white, but it does have them sort of TeleText color
codes (if that makes sense to you) each 8×8 pixel block can have a
foreground color and a background color and they’re actually in a separate area
of memory, so I’ve got some special commands to do that… because when you’re
dealing with the spectrum memory you’re kind of dealing with in two chunks… the first chunk needs to set your blacks and whites and then your second chunk is to
define what each block of those has as a color and if you watch very closely when
I’m drawing a RLE image you will actually see that happening in two stages,
just because the system is processing the black and white data first, and then
it’s processing the color data to overlay into the color area… so we will go
into that later as well… so we’ve got our background when doing routines now…
the background rendering routines they all really have to be in the
core for the spectrum… it’s not a problem because the I’m not supporting the 48k
spectrum so I don’t have the limitation that I do on 464 (64k amstrad) but
there is a rather annoying technical limitation with regards to the spectrum
screen memory, which I will cover later but so just for now to bear in mind they
all have to be in the core and then here we’ve got two commands this is relating
to running a command that is in a separate area of the system
memory… so we’ve got the first command which you passed the bank you want to
run and they memory address you want to call in HL
you then run the “define command” and then at the time you actually want to commit that action you run the “Call Defined” one this was so that I could use all of the
registers in the system when that final call was done, by pre defining it in
advance… so that’s just a sort of little trick I’ve done… I only do it on the
spectrum and I think it’s now probably time for me to explain why… so let’s just minimize this for a moment and let’s bring up my chart… so I
actually spent half an hour yesterday getting this ready and
hopefully we can use it to explain the different systems… so I’ve done three sections… there’s an Amstrad CPC section this is an ZX Spectrum section and
there’s an MSX section… so, the Amstrad CPC there were two versions… there’s the cpc464 which only has 64k of memory and then there’s the 128 KB version
now you can reconfigure the way the system works in a few ways on the
Amstrad CPC, and this is (I should point out) a real simplification… I’m not
talking about ROM… I’m not talking about some of the more special odd ram
banking’s on these systems I’m just telling you the basics of how my game engine treats these systems during the main game loop… anything else
(eg disk systems) we’re not going to talk about that… it’s just these are the
challenges the memory layout posed me and these are the work-arounds and I’m working with… so anyway, my game uses 2 screen buffers so it’s doing one screen while
it’s showing the other and then it flips them over… that allows me to change
everything on the screen… it means there’s no flicker… it doesn’t mean I’m
using a lot of memory, which is why I’ve only got 32k left on an 64k system…
so you’ve got Screen 1…Screen 1 is at the top of the memory… it’s at &C000 and then
screen 2 is halfway through the memory it’s at &8000 and then there’s two remaining RAM banks… now the first one is actually the ‘core’ memory (the core of my game code) on the Amstrad
CPC and the second one is the ‘level data’ now you should notice that the second one here is actually marked purple, and the reason for that is the
Amstrad CPC is a 64K system it’s only got a 16-bit address bus.
it can only address 65536 address locations which is 64
kilobytes (64k)… the way they get around this is on 128 K system is they have a piece
of hardware that swaps chunks of memory in and out… so that add an area of the 64
K memory disappears ,and one of the spare banks appears in the same place… great!
more memory! problem is… “oh well that was where my code was!… that was where my
screen was! I’ve got the sprites in there I need to draw them on the
screen!… you’ve just replaced my screen!” so you have to lay everything out around
the screen buffering, and work around it… so on the Amstrad CPC when I swap in the
extra memory banks with the extra sprites and things they appear in the
&4000 area which is great because my ‘Core’ is at the &0050 area,
so the Core is not affected the two screen buffers aren’t affected because they’re at &8000 and &C000… so everything’s happy!
and thatis why I’ve designed the system around that layouts for the
Amstrad CPC… now when it comes to the ZX Spectrum, we’ve got a very different
situation unfortunately so let’s have a look at that… so here’s the ZX spectrum now
the ZX spectrum at area &0000 it’s got ROM… and you can’t move it!
a quarter of the addressable memory area is always ROM
which is quite a problem… this is why I have to use Interrupt Mode 2 (IM2)because Interrupt Mode 1 requires you to change some bytes at a fixed location in
the first few hundred bytes (&0038) of memory We can’t do it (because that’s rom) so that’s Interrupt Mode 1 gone I actually used a custom RST on the Amstrad CPC… can’t do that because again you need to change a few
bytes in the first 100… can’t do it! and so… just in general, I’ve only
got three usable banks! rather than the 4 on the Amstrad CPC… so bit of a
challenge! that said, as I said before I am supporting only 128k spectrums
the spectrums… the spectrum has the same amount of addressable memory as the Amstrad CPC, it just doesn’t have as configurable the memory banks… you
do have these three backs here and you’ll see in the same ways as on the
Amstrad CPC.. you have a screen buffer 1 and screen buffer 2 and a RAM bank here… now this RAM bank here (you could probably guess) it’s actually where I
keep my CORE because it’s always in memory, and so it’s in a good position,
and just to be very clear… screen buffer 1 and screen buffer 2 before are not using all of these banks, as I said before now they’re under 8k
each …. they are using half the memory… but there is
another problem with these memory banks which… I will go into in a second, so as I
say… this is the the main addressable areas (48k)… you’ve got the rom here which
you can’t do anything with… you can’t get it out the way, so and this is why I said
before I’m using the internal font of the rom… because the Rom’s there
(Update: now not using rom font, for foreign language support) it’s not in the way of the screen memory if I use that font in the rom, then I can just dump it straight into the screen memory… so that was a good way
of taking it the best advantage I could have that fixed rom that I couldn’t get
rid of. so anyway, so you got screen buffer one, you’ve got screen buffer two and
you’ll notice here that screen before two is sort of in bold italic and
purple like this Ram bank on the CPC and the reason for that is is this area at
&C000 and above is the area that the system allows me to swap out for one of the
remaining five banks of 16k memory that the spectrum 128k has that I might want
to use, so that’s where I can store my sprites, my level data… my whatever else I
want… the killer problem is (you may have noticed) if my sprites are going to be
swapped in into the place of screen buffer 2 – and I’m writing in to screen
buffer 2 – that can’t be done… yes that’s a problem!
I suspect a vast majority of the games in the time actually used to get around
this by simply using software buffering (screen flipping) not hardware buffering
because the spectrum 48k couldn’t do hardware screen flipping… so I think that was probably the way they got around, it but
I am actually using Hardware screen page flipping on the spectrum… and so what I
do is if I need to copy a sprite from Ram Bank 3 to screen buffer 2…
so from one back three ran back threes I move Rambank 3 into the place of Screen buffer two… I then copied the spike data to a temporary store in here in the core…I then swap the screen buffer to back in and then grab the
write the data out from the tenth we buffer from here into here… it should be
slower… but actually you can’t really tell the difference… logically every other frame should be slower, but it doesn’t seem to make much
difference and again that may come down to the fact that the spectrum he’s
actually got less data to push than the Amstrad CPC, so ironically becomes
faster… but anyway as I say that’s a problem… would you believe even all that
lot isn’t bad enough… it gets worse! some of the memory banks are slower than
others because of the way the screen addresses the memory… this Bank here and
this Bank here are actually slower than this Bank here, and you’ll notice some of
these banks are in light grey here… these are actually the fast banks and these
banksare the slow banks… on the plus three they didn’t keep it consistent… so on the 128k spectrum these two banks are slow… on the plus three – these two banks are slow… so yeah thanks for that guys… so I try and use ram
bancks two and zero for your most important stuff… two is where I keep the
core… zero is where I keep my level data and then these.. I don’t know! I mean at
moment I’m just treating them all the same… I haven’t noticed any difference
with testing on the +3 and the 128 if I was going to be really
dedicated about it I would detect what kind of hardware I was using… I’d swap the banks
around in the program using self-modifying code… we’ll see if I can
be be motivated to do that or not
(Update: I was not! banks unchanged on 128/+3) because as I say it’s going to be a lot of
work,going to mean some testing… if I can’t notice the difference, maybe I’ll just
let it slip… so yes that’s the “lovely” way the spectrum works with its memory…
I’m criticizing it… it works okay you can get around… it it’s just when you
look at the relatively logical way of the Amstrad CPC, and then when you look
at the spectrum…
where you think “Why did they do this to me?” I suppose that’s what you get for using thirty-year old
computers… so finally onto the MSX… the MSX as I’m treating it… the MSX is a
heavily upgradable… but I’m considering an MSX to be and MSX2… I’m considering
it to have 64 K of memory I’m considering it NOT to have a memory mapper
which allows more advanced swapping of memory and I’m considering it to have
128K of VDP memory… which is graphics memory with the Amstrad CPC and the
spectrum, the graphics memory is actually part of the main system memory – they’re
one in the same thing – so you poke a byte to &0000
you corrupt the system your poke a byte to &0100 you store it in your game data you poke
it to &C000 it appears on screen it’s that simple…. with the MSX – nothing like that!
you have a separate processor it’s a dedicated graphics processor… you’re
literally you’re doing multi-threading you tell the graphics processor “I want
to filll part of the screen… it goes “okay well I’ll start” and later you ask “well have you done it yet?”
and it replies “I’m still trying! give me some more time!” and if you tell it to do something else it’ll get confused… so you
actually talking to two systems and they’ve actually got their own memory… so
the MSX Z80 CPU has its own 64K memory here… so there you go
that’s what you got… it works just the same as the CPC no bank swapping… and even though
it’s only 64K compared to the 128k of memory on the Amstrad, it’s actually
ends up being more… because although you’ve only got 64 K of data memory,
you’ve actually got this magical 128K of graphics memory, which
is totally separate… you can’t directly address it… you have to send
requests to the vbp to do things with it but it will do them, and if you play
your cards right it’s actually faster! because you’ve actually got two separate
processors, you’ve got a Z80 CPU doing all your logic work and then you’ve got a VDP good graphics processor which is
doing all the dirty work of commands like “I’ll fill that area to the screen with that sprite – I’ll get on with this”.. and that’s why I said earlier the the Tile array on the
the tile areas of the background on the spectrum are 64 pixels wide… on the MSX
they’re 256 pixels wide the reason being it can actually do 256
pixels once faster then it can do 64 pixels over and over again across the
screen… so it’s really working out how to work with these systems… so the
MSX uses 128K of video memory so and each screen is almost 32 K (actually 24k) so twice the
Amstrad CPC the the the screen size is 256×192… if it was 256×256 it
would actually be 32K… and what I’ve actually got for you now is I’ve
actually paused my game running with the screen memory in a debugger and I will
now show you what the screen memory actually looks like if you were able to
rip open the VDP and look at the screen memory so let’s bring it in…
so here is the debugger of the openMSX and you can see this is my game running…
and what we’re going to be doing is we’re going to be playing with this “show
page” option here… which relates to these VRam screens that I’ve marked up
here so 0 is my first screen buffer and then if I just press the down key you’ll see Ijust flipped to Page 1 and you can tell the background has scrolled
slightly… and what you should also notice at the bottom is “There’s some
strange stuff there! what’s that?” well that’s actually our player sprites and
our boss sprites and so if you can’t figure it out I’ll just explain…
what I’ve done is because the VDP is basically copying chunks of
screen memory to other chunks of screen memory and as far as it is concerned
it’s actually got this one huge long screen it’s a 1024 pixels tall by 256 wide… that’s the way it thinks of its screen memory
and so you say “oh I’ll copy that sprite down from the bottom of the screen which
would be the “Chibiko facing up” sprite and then copy to the actual position of
the player sprite and that’s what it does, and it doesn’t care (if it’s onscreen or offscreen) the only person who
cares is me when I’m trying to figure out how the heck to convert my sprites
to work in this weird way!… it’s perfectly a right way of doing it… it’s just a pain!
when converting from CPC for the spectrum, it took about two hours to convert the sprite code… and converting for the MSX took about three weeks because I had to rewrite my graphical routines…
but anyway that’s another story! so as I say you can see the player
sprites on screen now… and if we go to page one, you can see the first part of
the the boss sprites and if we go to page two, you can see more of our sprites and
the actual background tiles… and then finally a few remaining bits of
backgrounds… the bones which aren’t actually used by this version… that’s
only for the v9990 version… but they’re even here anyway… there was some
spare memory… some black area here which is just spare ram…maybe later levels with bigger bosses owill need it… I don’t know… difficult to tell at this
stage! someplace right here for the icons in the corners of the
screen, and the system font right at the bottom but these at the bottom so
there’s plenty of space for the levels when I’m developing these games… when you are
designing things, you are always sort of thinking “well what am I going to need
later?” and the answer is often “I haven’t decided yet… I’m not really sure…”
I can’t say right now how much sprite data I need for the most complex level
in the game… I can’t answer that until I’ve done it… so I’m having to make a
guess basically if I run out of screen memory I’ll have to make the sprites smaller
(Update: I didn’t!) it’ll come down to that! but as I said you see you’ve got four pages here
and the thing just to reiterate is don’t think that a sprite split over two
two pages makes a difference when copying… as I said before the system
treats this as one long screen it’s not for screens as far as the VDP is concerned so hopefully that’s explained a
little bit further how the screen memory works! maybe that makes a “bit” of sense to someone!!! just to very simply recap… the ZX
spectrum considers the memory of banks to be 0-7 and the I’m Amstrad CPC
considers them to be &C0 to &C7 (very basically)
you’ll see that kind of terminology floating around the game
code a little bit… so as I say, I’m being over simplistic… the Amstrad CPC memory
banking has a few other tricks up its sleeve… but for now just you know just
sort of consider it from how I’ve described there… because it’ll get you
by for understanding the early stuff at least, so lets find my assembler and get on with the description… then so we’re back into the assembler
now and we’re going to have a look at remaining of main chunk of the
jump block… which is common to all of the systems, so the first one you’ll see it’s
called “execute bootstrap” The “bootstrap” is the bridging point between each of the levels, and it performs jobs like
resetting the core… a lot of its purpose was to break out some of the
essential system commands which were required but were not
required during gameplay but were required at all times (all game levels)
and the reason for this is I actually had to remove it from memory
during gameplay on the 6K CPC because there’s no memory left for it so it’s
actually loaded into the memory area used by the second screen buffer
and it does jobs like setting up the core, loading the game levels,
showing the continue screen, various of the little jobs like that that that
don’t need 2 screen buffers (which you do need in gameplay) but are completely
essential to the game… it couldn’t work without them so it acts as a bridging point, it’s
got one entry call point which is “execute Bootstrap” you give it a
command number in HL and it goes and does whatever you’ve told it to do! and
resets everything and make sure everything keeps working again and make
sense makes my life a lot easier! so it works very well! “Show compiled sprite” is a command
to show a full-screen image on the 128K Amstrad CPC, like the loading screen,
on the 464 systems it doesn’t do anything because there’s no memory for those
large compiled sprites… so that’s what that does… “show sprite” is my main sprite
routine there are different versions for each
of the operating system for each of the systems… the Amstrad CPC and Spectrum
version are fairly similar… the spectrum version is just half the size of the sprite
that’s drawing… and then it has to do a little extra bit to do the color
information… the MSX version is completely different, of course it’s also
a lot smaller! the MSX version is actually the most simple because all the
work is being done by the VDP, and so it’s “swings and roundabouts” I have to do a
lot of work to get the MSX version working, and to do a lot of changes to
the code to get it working… but it’s actually quite fast, and of course with a
V9990 version – ridiculously powerful! so then the work supporting the MSX2 has
paid off in both ways… while it’s very different to the other systems, those
differences can reap dividends if you use it right! “set bank address” this defines
the memory starting point of my sprite information… I’m going to do a proper detail
document on my, on how the sprites are defined in the system’s,
because all three systems (even the msx2) actually use a sort of common sprite structure, and the spectrum and Amstrad
versions use almost the exact same sprites (in terms of data format) I will give some real proper
documentation on that (very technical documentation) which describes the
binary format of the files all of the binary sprite files I create are
actually created using my sprite editor… I’ve created my own sprite editor… it’s a
simple little thing, but it can export into various formats, can compress to RLE…
can do compiled sprites for the Amstrad CPC… does it all and is open source and available now! so if anyone feels
like they want to use it … great, go ahead! and if you want to take it and rip
it apart… make it work properly(!)… make it look like a “proper” editor… go ahead do that
too…. I fully encourage you! anyway so yes I’ll be describing those much better
later… “get sprite XY”… that gets the coordinates the last sprite that was
drawn… that’s mostly used by the MSX version, because the font on most of the
systems is actually a bitmap sprite as I’ve said before, so it’s actually… that effectively gets the current text cursor position if you’re drawing fonts at the
time… this is a dirty trick that I use for the amount for the episode 2
where my boss is the bus why to enormous in Ep2 and I have to do all kinds of tricks to keep them fast too… I
have to break them into lots of little sprites… but the game engine is really
designed for square sprites, and then the clipping doesn’t work.. so I’ve had to do
a few dirty overrides and tricks and things… the these kind of rare commands
are the things that should really be in the vector array… they are only used by one
level or once or twice… they shouldn’t be in the core, they should be using as little memory as possible… and “force now”..
again the “event stream” is going to be something I’m going to explain properly
later, because it’s a complex thing! the “event stream” is the
objects that appear on the level as the level progresses… it also does things
like the main menu… the main menu is actually an event stream… everything is an event stream
anything that’s timed is probably an eventstream… so like the opening sequences
are events sreams as well… but this is a way of forcing events… usually an event occurs every few frame refreshes… but sometimes you needed to happen right now… and that will force that right now! some commands relating to configuring
this scrolling of the system… scrolling effects the gradients… the gradients are
with are in the core on the Amstrad CPC, the more complex backgrounds (the tile
strips and things) are not in the core on the amstrad CPC, but also apart from
the gradients the background objects themselves have a very slow move speed which
is part of the background parallax and those commands
will re-configure which direction those background object need to move, for
the vertical levels and things… so that’s what those are for. Now, here we’ve got
some commands related to music… all but the last of these are essentially…
I use ArkosTracker for the music and sound effects, so all but the last one of
these are just saying “hey ArkosTracker… do it,get on with it!” they just point us straight to ArkosTracker… the final
one… PlaySFX is slightly different, only apply one sound effect per frame update, so all it does is it says “hey I’ve been planning to make a
beep – unless anyone else wants to do anything” and then another thread will say “hey, well I want to do a big explosion”… and well and big
explosive noise is more important than a beep so “you had better do your big explosion!” it’s a simple thing… you give it a number from one to five (or something) and that’s the five limited music effects that I could fit into 1k of memory that I’ had left and then the player plays the effects… it protects the registers as needed using pushes and
pops, and it decides which sound effect actually needs to be played at
the end of the day… that’s what it does very simple and it allows me to make a sound
who just rwo command… 1. load a register with the sound number 2. call the function… and then
interrupt handler… what that does is it turns on my custom interrupt handler, which on the MSX and spectrum just plays the music, on the Amstrad CPC, it’s much more complex… it does
the raster color splits… so very tricky, on the Amstrad… and
there’s actually two versions on the Amstrad… the CPC plus version has a
different one, because the Plus version is more advanced… so and these ones are
related to what I just described allowing the interrupt handler to be
switched to disable certain functions while keeping other ones running,
so again, more fun with the interrupt handler… and then here you’ve got some
more commands relating this time obviously related to the interrupt
handler but these are defining… this is the bank of colors I want to use (for the raster switches)…
reset them I want to start again because I’m loading a new level… and turn them
off temporally, I need to show the continue screen… that kind of
thing and here’s some more… black out just sets all the colors to black… just
so well I don’t want to show anything I need to draw thee game over screen
or something, and then default safe is the sort of “system palette” which is
black,purple,cyan and white again just quickly
“hey I need to show this continue screen just give me some proper colors and
don’t crash it the interrupt handler with any old junk” that’s all they do… now these are the
Amstrad CPC bank switchers… as I said before… on the Amstrad CPC
they use &c0 to &c7… on the spectrum they use 0 to 7… there is a spectrum
equivalent, but they’re actually the same commands… and then on the MSX they exist
but they don’t do anything because in the MSX, I only treat system
as 64k… so there is no back swapping so they exist just for compatibility,
just while I was picking through the code and putting my conditional
compiling statements on everything… the dummy routines are there so that you know the system doesn’t
try and run them anymore on the MSX “object array”…this draws the
(I mentioned before) the event stream is the events that happen in
the level… most of the events are “create an object – there’s a new bad guy coming” or “hey do a gravestone in the background” and those
go in to the object array… so drawing the object away basically draws
all of the sprites that make up the background… the bad guys and that kind of
thing… they don’t make up the player which is next of course!… “player handler”
that reads the joystick input works out what the key is and joysticks buttons are “down” and how they actually relate to the player… by which I mean if the player has a
redefined a set of keys which is eight possible different keys, “well ok the
players press the P button! – does the people mean anything? well it means pause…
ok we had better pause the game” so that’s what the player handle does,
draws the sprites… if the player has got 2 fire buttons down it goes
to the 2-fire-button code and fires bullets (if the players got enough points
to do that that kind of thing)… so all of it’s done by the “player-handler”r and then
there’s a separate section called DrawUI the reason it’s in twp parts… the UI is at the top of the drawing stack and the player sprites in the
middle… and the bullets are above the player… so it’s split into two parts… that
shows the score and the lives the smart-bombs… things like that.
We’ve got a “Read Controls”l command which is another part of it… while the player
handler will do this kind… there are times when I need to read control, but
should not show the player… for example even the redefine keys command uses it and “press fire to start” I need to read the keys… but don’t want to show the player… so I use
it for that… the up/down buttons on the menus… things like that! so we’ve got
to “get player vars” about which is a very important command… the entire game
engine uses about 48 to 64 bytes of user memory – which is everything from the
place remaining lives the keys the players controlling the
game with…. the high score… what computer that systems been detected as (eg 464… 6128.. cpc+) for
example… all of these are in the “get player variables” they’re saved to disk
when the system shuts down… when the system starts… at start up they are
reloaded and in some cases like the detected hardware version, they are
overwritten as the startup… works very well! “what am i running on?… I’m running on a turbo-R today – ok well I better make a note about just in case the system needs
to reconfigure the level for later” that’s what the “player vars” are…
very important! really used a lot for configurable stuff… “Get HighScore”
I think that probably barely need… these probably… I think that must be used by
the main menu and that’s all! again that’s the kind of thing that should be
in that Vector Array… complete waste of a byte of memory being in the core…It’s been so long, I can’t even remember what use it is! “hit player injure”… these simulate the effect of the player being hit by a bullet and these
are for the the so called “Omega array” of the last level the
normal game has a 256 bullet array… the last level has a 1,024 bullet array (now 1280!)
which is actually contained within the level data… and the reason for that is it
uses a lot of extra code.. it’s very big, firstly the sheer memory it needs to
store that many bullets, you need three bytes per bullet… so you are ending up with about 8k a memory just for the bullet
array, and also so many bullets… you’re going to use every trick in the book to
speed it up… self-modifying code, Vector arrays your name it… it’s using it…
but the thing is even though it’s in the level code it needs to be able to to
fire the normal “player injured” routine as if it was in the core, and so
these are the entry points for if a bullet hit player 1 and player 2…that’s
what those are for… “Player Star Array” that’s the the star arrats are the bullets… so the players
bullets are drawn with the player “star array” and the enemy bullets are drawn
with the main star array… they’re actually almost exactly the same code… just
different bits switched on and off depending on… if it’s the the player shooting…
well I don’t check if you hit the player! because that makes no sense!…
things like that – so the’re almost identical, just little tweaks here
and there… “Star a palette” that allows the game engine to redefine the
colors of the enemy bullets… which is a trick used on the EP2 – level 4 boss …where
the bullets are actually supposed to be different objects… which is a bit of a
joke in that, but it’d be very nice on the V9990 version
because then, that can actually have proper nice sprites for the bullets as you
saw from the bones earlier… it was a kind of quirky effect
on the Amstrad… but on the on the MSX on the MSXV9990 it would be really good… so and “Fire star” that’s used by some of the enemies…
some of the enemies in the game have their own special code
that handles their movement in in the first version of the game (episode one)…
the game movement only allowed very basic movement for the enemies
so things like the rabbit (the jumps)… in the second level… that
had a lot of very custom assembly code tagged into it that allowed it to do
that and so this “fire star” was used by that… with Episode two I realized it
was really dragging down on the debugging time, so I created a new
function called “animators”.. which is where it’s basically a software scripting language (almost) where you can define a set of
patterns that each enemy follows and having some simple conditions in there
and then so on… (so this function) it’s kind of redundant this kind of thing… but for compatibility
for the speed of getting episode one out I’m still keeping them in it… as long as
something’s not broke I’m not fixing it I just want to get the game working
get it out there… so if it’s worked all this time in episode one with the
complex compiled code assembly language… well great! I’m not going to change it –so that’s what tha’s for… do
“smart bomb call”… this simulates as if the players just used a smart bomb .. without deducting any of their smart-bombs… the reason that is the end
of a level… I didn’t wantt the player to hit any of the last enemies as the
game screen faded out, so there’s always a flash at the end and all remaining
enemies die and turn to coins… so that’s what that dos.. so it’s called just as
the level shuts down… I will go over it a little later, but at the moment I’m
redesigning the level structure quite a lo… because the new
version 1.666… it’s based on version two and then some it’s got a heavily
upgraded structure… there’s different branching parts for the different
different platforms…. the v9990 has got a different version too,
– and the spectrum and the amstrad versions are kind of very intertwined…
I’m still trying to get it neat and worked out and clean in my own head…
I don’t want to show people a buggy version I’m going to get it right first… so just bear with me…So “StreamINIT” that’s what executed when the level starts. it says “hey here’s my set of events that’s going to occur in this level” the system loads it in… sets all it’s
pointers and gets ready to go eventually process (actually run) the events… it
doesn’t draw anything – that’s done by the “object array redraw” but event stream
processing over “what time is it? okay well it’s labeled level time 5 –
does anything happen at level time 5? oh yes this kind of skull-thing flies in
to the screen! I’d better get on with that then!” again, I’ll go into improper
detail later… so “get level time”… well as I just
said everything in the game level has a time… and so sometimes you
want to know what’s the “level time” and then do something with that…
levels use that kind of thing as some of the advanced code as I’ve described for
moving enemies around might use the level time to decide how to what
direction to move the enemy at this point or the game engine may
read the level time to work out whether the bad guy is still talking in
episode two or something like that… the level time is used in
various ways.. “set level time” related and some a lot of times the game engine
actually moves itself around the level times, so for example the boss… if you
haven’t killed the boss yet the level will loop and loop until you do once you’ve killed the boss, the level
will jump out of that loop… and jump to the end level section of the code
so that’s what “set level time” does “Load Disk sector” that loads a sector from
the disk this command exists on all the systems I use a numeric reference for my
files and there are different versions of that command for all of the systems
the MSX version and Amstrad version different versions… and would you believe
there’s three versions of the spectrum… because the spectrum has three different
disk systems… if you’re interested in finding out more about that I’ve posted
a quite technical and description on my patreon account… so please follow me on there if you want to really see how that works
“Load Disk SectorZ” exactly the same only yeah it’s loading file, it’s at LZ48 compressed… so once it loads it decompresses it into memory… again that’s
in that document I just described… “Firmware Kill” it’s called that because on
the Amstrad CPC 464, the firmware variables are actually deleted from memory… because the
firmware has some temporary data in the screen buffer area of screen
buffer 2 which I need for the game obviously… so “Firmware Kill” wipes it out…
it makes a few backups of a few very important bits first and “Firmware Restore”
puts it back again… but the way it puts it back is it calls the system firmware
the system rom and says “hey well you know … could you set yourself up again
please?” and then once it’s done it pushes bits of data back in like the
“current disk number” and things so “Firmware Kill”and Firmware restore” very advanced on the Amstrad… they don’t do anything like that on the spectrum yet because
I’m only supporting 128k I’m quite conservative, and I haven’t yet found out
if we look ways of doing things like that that are going to work on the
spectrum … the MSX does have some firmware variables as well… they they kind of go
from &D000 to the top part of the memory range… a bit of a pain
but I’m able to work with it… they’re not causing me any problems yet, because
the game was designed around the 464, with its 32k memory limit (after screen buffers).. the
48-56k of remaining memory on the on the MSX is more than enough…
I did actually consider RLE compressing it and storing it into
videogram or something really cunning at one point… but I’m trying to avoid
that because I suspect I’ll regret it… if it doesn’t work with very obscure disk systems or something…
so “Sprite Bank Font” this uses my bitmap font on the Amstrad CPC and MSX
on the 464 for where I’m using the internal font and on the spectrum it
configures the system to scale down the system font if required (Update: Spectrum now uses bitmap font too)
chibi Akumas uses two fonts which you could probably just, you may have seen
earlier…. you’ll see this to sort of Fonts here and the main one is of course the
big one and then the miniature one is for the “on screen interactive insults” in
the second game where the characters start abusing each other, and YES… it was
solely designed for that! so that’s a very important function!!! so yes there’s
the normal font and the half-width font, as I said before, when it’s not a
bitmap font on the spectrum ,the 464 it’s actually scaling down in real
time the font of the internal firmware one ..which is a slight reduction in the speed on those
systems… but again what can you do? so here we go “Locate Sprite” and “Locate Sprite for carriage return” these emulate the built-in firmware
functions of the Amstrad CPC… so you can locate by HL register a position on the
screen… it’s done on an 80 by 25 screen… even on the spectrum and MSX which don’t
have that much width… I have to have done
some documentation on the screen layout on Patreon… it’s it was all based on the
320 by to 200 screen of the Amstrad CPC and then it was sort of altered for the
other systems just because… well it’s all working… I don’t
want to change everything! “CharSprite” that draws a
single character based on bitmap fonts… “draw text print string”…
well that just prints an entire string something quite curious… I
can’t remember where I got an original code fragment and the lines were
character +&80 terminated so you would add 128 to whatever letter with the last
letterin your string… and that would be considered the end of line… clever
trick, because it saves one byte… you know if you had a carriage return at the end
of a line that’s one byte “On it’s own”… but now you’ve got a letter and an end of
line command combined… that’s great however the new version of Chibi Akumas is actually going to support Japanese… I need more than a hundred and twenty seven
characters now, so I’ve had to redesign it so for non default languages
(which is basically English) the line is now terminated by a character 255
which will lose a few bytes here and there, again as I said before learn be a
problem on the MSX, probably could be a problem on the Amstrad CPC… just to
describe how bad things are on the Amstrad CPC version the new plus version
is going to have eight color splits down the screen…
I couldn’t have nine because there’s no memory left, and each one used about 20
bytes… I’m down to bytes! anytime I see a byte I can reduce in the code of the
core, I take it out because that CPC version… if I find a major bug and I need
of a hundred bytes to fix it … that’s serious problem! there isn’t 100 bytes left ! so yeah… wasting a byte but again as I said before, MSX , Spectrum version… no
64 K support… no problem so “DrawText Decimal” that just converts 1-10 in A to a number on screen so &40 and shows it on screen… something like that! “decrease lives shot” that as it says onscreen somewhat some
of the objects have custom hit handlers which is where the bullet hits the
object and the object can decide “well I’ve been hit but do I actually want to
process that and? if so how” that’s used heavily in Chibi Akumas Episode 2…
things like the Thermonuclear missile launcher if you shoot it.. it explodes!
that’s a custom hit handler! the boss battles as well “custom hit handlers”… “oh
well I’ve been hit but I’ve got a life of 255 so I’m not
going to decrease in any normal way… I’m gonna make all of these decisions first…
well the player has hit me… but you know I’ve still got life left so I’ll keep going
for now, and then when I get to this point I’m going to change my sprites
to show I’ve been injured”… the “decrease life shot” is kind of the end point where “well
okay I’ve done my special process and just treat it like a normal
enemy injury”.. so “screen buffer flip” … “Screen Buffer Init” sets up to screen
buffers … “Screen Buffer Flip” swaps them over… “screen buffer reset”… that sets both
the active and visible screen to the main one
so that’s used on the menus… used on the game over screen… I know you because
I said before used anything but the bootstrap calls on the CPC… the bootstrap
is in the location of screen buffer 2 so there cannot be two screen buffers… so
“screen buffer reset” is kind of the same as your Amstrad CPC screen would be when
you switch the computer on … so “Screen Buffer Alt” I think that’s used during the intro sequences or something… it might be redundant no,w not really sure!
it might be a bit of a sort of dinosaur of the code there! I’ll check that out… maybe
a few bytes I can save later! now here we go, here’s the big one! as I said before
the screen memory on the Amstrad CPC and spectrum is actually part of the system
memory, so when you want to if you want to draw a dot in the top corner of the
screen what you do is you work out where that is in memory then you just poke
the byte in memory… chibi Akuma’s… because there was enough memory
left in the last moment I was able to have a lookup table for the screen
locations rather than calculating them which is slightly faster! so get next
line moves down… the lines aren’t consecutive, you can’t just write 80 bytes (one lines worth) across the screen and then end up on the
next line… you end up jumping down ! it’s kind of interlaced… it’s weird on the Am strad… it’s even weirder on the spectrum… I’m not going to go into it here!… (I have another vid on that)
so “get next line” works out how you move down one line… because it’s not
simple… get Screen Address Table gets the lookup table… that’s again relating to the Omega Array on the very last level where I was calculating everything
myself… “get mem pos”… you give that an XY coordinate and it returns the Memory location for that co-ordinate, anyway so and then “get active screen”… that returns
the current screen buffer, because as I said there are two…on the Amstrad CPC that
will return &C0 or &40 because that’s the starting point to those
memories of those buffers… on the MSX will return either &00 or &01
which you can add on to the Y coordinate and that will give you
either 256 Y-start or zero Y-start because the second page is 256 lines
down… and on the the spectrum as I said before it’s &40 or &C0…
you saw the chart earlier, that’s where they are… and then we’ve got some and timer functions and chibi akumas… as well as the level time has a tick timer… a tick
occurs every frame on the systems… and so if you
want if you want something to happen in every fourth frame, you
can process that by what ticks occurred it’s probably one to describe in
another video or a text file or something, because it’s quite it’s
complex… it’s simple but it needs to be understood… I said it’s not always
true that it occurs every frame… because on the V9990… the frames occur so fast
that in some cases you have to ignore every other one… so anyway that’s the
ticks and then “sprite banks switch”…this allows
you to change the sprite banks… as I said before the
128k systems have 4 sprite banks and this is just an
interface to allow the level code or whatever to switch between sprite
banks and make the current enemy use the fourth bank or the
second bank or the third back there I said forurth… I should have said they are numbered from 0-3 “Do Moves”.. that is something I
think I’ve briefly touched on… I have a briefly touched on that on Patreon… all basic objects in the game move in one of a various linear
directions… some objects (like coins) will fly towards the player… other objects (like
background object) move very slowly in one direction and the do move command
does all of that… it handles all of the movement of background objects, and a
stripped down, more limited version does the bullets movement… it’s not the main one
because the main ones too big and complex for the bullet movement… it just
had to be even “make it as fast as I can” so I stripped it down… the “object spawn” well
that’s explained there… that’s a way of creating a new object, without
using the event to write things like zombichu… the boss of the second
battle will blow kisses at you.. the kisses appear… and so that I think that
is used for that… that’s a way of special code creating special objects…
“Hide Sprites” that switches off the CPC plus hardware sprites.. that
should really be in the plus block because nothing else should ever need to
do that… and another Vector Array which is these vector arrays are only new
for the v1.666 version because as I say I keep needing new things …. core
keeps getting bigger so I’m
trying to start using those just as way of making things a little smaller if I can…
and it helps as well because the the what the MSX needs, and what the
spectrum needs, and what the Amstrad CPC needs in some cases are wildly different!
the Amstrad CPC has got 20 commands and the MSX is using a VDP for those commands, so it doesn’t care about that so I’m splitting them out into
vector arrays, so that I can have certain commands on certain systems and
not others, and just as I say you use two bytes instead of three… so okay well
that’s all of them… so we’ve got a definition of where the level start is…
the level data itself has a tiny jump block of basically two commands… one of
which is never used that’s just a pointer to that.. so those
have to actually start the level code that’..in episode 2 there’s a joke
where the main character walks off the screen and refuses to play anymore… as
the main game as the main level code would actually render both characters
that couldn’t be used so I’ve had to add a special piece of code that will run the “draw players code” from the second player… that’s the kind of thing
that should definitely be in the vector array… there’s no justification for it here, it’s used once by one game, and it can be slow…
so that’s the number of bytes between the two players data.. remember I mentioned
before that there was a memory block of player variables and things like that?
well there is 16 bytes for the first player and 16 bytes for the second player… so if
you want to jump to the second player you run the main command and then add 16
to it and you’ve got player 2 so just to save having two block entries… for “get player 1” and “get player 2” and here’s the key map definition… as I
said before there’s eight key presses which is represented as a single byte,
and that is the layout… the reason that the reason that the layout is a EQU definition is
because I had to change it I added support for the “multi play”
Coincidentally.. the multi player used almost exactly the same concept of a single byte for controls as I did unfortunately it used them the opposite way
around, so I had to reverse all of my controls.. no problem but rather than having them hard-coded in we’ll put them in as definitions here and
then if you want to know… Chibi Akumas uses 2 fire buttons… if you want to know if the the player has hit either one then you can just use this here.. OR it… and
then just see if you’ve got a fire button hit or not… so
there we go… and then here… the very bottom… you’ve got
some definitions of the variables used by the leve…l I’m not going to go into
them here and the reason for that is those aren’t really the definition
locations are valid…. but the data definitions in there might be a bit
misleading, because as far as the system is concerned all that needs to be true
is that area is blank… it doesn’t need anything in it… the other areas of the
core that wiped that and we convert some… I’ll write a proper description later of
how the the game variables, the bullet arrays work, the object array…
how their data is stored and I won’t go into in this video, I think this video
has gone on long enough and I’m sure everyone’s got bored and giving up or
something like that! well so I think we’re at a point where
we can pretty much wrap this one up! I think we’ve gone on long enough…
I’ll just leave that open because it looks quite nice and I will just say
thank you… well hopefully this video has been interesting to someone out there somewhere!… if people are interested in hearing more like this then please let
me know! if you have a particular direction you would like me to pursue… if you say “oh well Keith we’re not interested in assembly… but we’d
really like to hear about how memory mapping works” or something crazy like
that then just let me know I’ll try and do it… if you want to know more serious
stuff please consider following me on patreon because I’m trying to do
text-based stuff on there… I’m trying to write games and I’m trying to let it all
know how frustrating writing games can be, and how fun it can be as well (maybe
sometimes)… so yeah please just consider that follow me on Twitter
whatever! so going forwards if people are interested in these videos I’m going to do
more of them! I have this crazy idea where maybe one day I’ll them I’ll
create a mini version of the game which will be free and open-source and it will
actually include documentation including these kind of YouTube videos
documentation on how to actually create your own level from scratch… even if you
know no coding at all! it would be a sort of staged tutorial where the beginner
stage would be if you know no coding create some bitmaps of the of your
enemies.. run them in this program… copy the files onto this disk image… run it in
your emulator.. you’ve just re-skinned the entire level… the next stage would be
“okay well you’ve done that maybe you want to move change the way the enemies
move, change the times they appear, change how they shoot” this is how to do that…
and then the next stage again would be “well okay
you’ve managed that just fine here’s how to completely redesign the level.. change
everything about it” and then the next stage again would be “this is how to
write your own game using some bits of mine” so I’ll do that if that’s interesting
to someone …if it’s interesting to people I’d be interested in making it if people
be interested in hearing about it ! if it would give people the
skills or experience or confidence to make their own games like this, then I’m
happy to do it! as I’ve said before my games are all written in Assembly
language… I can’t do that in C++ or anything (the tutorials)… I’ve done C++ before but my
retro gaming development is only in assembly language so please bear that in
mind… don’t ask me to do that for C because well that’s me starting a new
game again! but as I say if that’s an interest to anyone please let me know!
give me give me some comments Let me know what you think of this stuff!
Thanks a lot!… goodbye!

3 thoughts to “Z80 Gamedev for CPC, Enterprise and MSX – Coding a multiplatform 8 bit game in assembly”

  1. I didn't get bored or give up! This was pretty interesting, I do love how you've approached this problem. I'm writing games for a Z80-based machine as well so you have a new follower

Leave a Reply

Your email address will not be published. Required fields are marked *