Screen routines

2

Comments

  • edited January 2012
    joefish wrote: »
    If something was ready early its production run could be brought forward to avoid any further delays then stockpiled until the right time. Meanwhile the programmers could be given a new task.

    The idea that there'd be time in the schedule for faffing around with gameplay tweaks, rather than people working overtime debugging the code right up until the last minute whilst simultaneously working on two other projects (which is what actually happens) is some sort of fantasy world of professional software development.

    Amazing that manic miner and JSW were both written in 6 weeks according to Matthew Smith. How on earth did he hone the levels and gameplay so finely and write the engine in that timeframe?
  • edited January 2012
    joefish wrote: »
    If something was ready early its production run could be brought forward to avoid any further delays then stockpiled until the right time. Meanwhile the programmers could be given a new task.

    The problem is you didn't read what I actually wrote. What I said was that the technical side of the coding was usually finished in the first couple of months - not the whole entire fully working game. With the engine completed and working then those remaining four months would be used to implement the game (and gameplay) itself and not keep tweaking and rewriting the core routines to get just one more sprite out of things. The core code routines would be in and working and the majority of time spent getting the game to play well - by writing the non-engine code and getting the playability down as good as it can be.
    joefish wrote: »
    The idea that there'd be time in the schedule for faffing around with gameplay tweaks, rather than people working overtime debugging the code right up until the last minute whilst simultaneously working on two other projects (which is what actually happens) is some sort of fantasy world of professional software development.

    If you've ever coded a professional game then you'd know that "faffing around with gameplay tweaks" at the end of a game is the bane of all developers as your Producer or the license holder will start making all sorts of 'suggestions' as to how the game could be made better as the end approaches. It's hard enough fixing bugs without having to drop everything and implement some new twist or feature just because they are paying the bills. They will tell you the game is too hard or too easy, they will tell you it's too fast or too slow, they will tell you they don't like the look of the main character now they've had a chance to play with it for a while. You get the idea. You can try and argue them out of it but at the end of the day they pay the bills so you have to change things.

    I wish it was just a fantasy, there isn't time in the schedule for faffing around with gameplay tweaks, but when you are told to do so you do so and grit your teeth.

    BTW If you were finishing off a game to a deadline and the software house found out that you were working on one or two other games at the same time (i.e. not giving your all to finish that one) then you wouldn't work for that company again. And that is a fact.
  • edited January 2012
    torot wrote: »
    Amazing that manic miner and JSW were both written in 6 weeks according to Matthew Smith. How on earth did he hone the levels and gameplay so finely and write the engine in that timeframe?

    Six weeks!? Amazing - it has taken me over a year to write MRT and that is in ZX BASIC with lots of help from WOS and BASin!

    Matthew must have been and/or is a great programmer.

    Paddy
  • edited January 2012
    joefish wrote: »
    If something was ready early its production run could be brought forward to avoid any further delays then stockpiled until the right time. Meanwhile the programmers could be given a new task.

    The idea that there'd be time in the schedule for faffing around with gameplay tweaks, rather than people working overtime debugging the code right up until the last minute whilst simultaneously working on two other projects (which is what actually happens) is some sort of fantasy world of professional software development.

    Finishing software ahead of schedule - I am sure it must happen but not in my experience. :smile: You have a delivery/GA date and to hit it you normally sacrifice functionality to maintain quality. You can do the opposite but that does not normally build a long term business.

    Paddy
  • edited January 2012
    I don't remember details but I read on these forums that Manic Miner engine is actually very bad and inefficient from a programmer point of view (something like redrawing the full screen each time, I really don't remember). Someone here did a modified version of it working twice (!) as fast.

    But it still was a great game, just like first Dizzy which again I remember to read that it had a very bad, ugly code :)

    Generally you can do a good game with not so good engine and vice versa.
  • edited January 2012
    Turkwel wrote: »
    BTW If you were finishing off a game to a deadline and the software house found out that you were working on one or two other games at the same time (i.e. not giving your all to finish that one) then you wouldn't work for that company again. And that is a fact.

    If I was a manager and had someone working on a game, who I found out was laying the foundation for another game or two, while still being able to finish off that first game on schedule, I'd make sure I kept the programmer employed.
    ...not all games development are a mad rush towards the end.
    Website: Tardis Remakes / Mostly remakes of Arcade and ZX Spectrum games.
    My games for the Spectrum: Dingo, The Speccies, The Speccies 2, Vallation, SQIJ.
    Twitter: Sokurah
  • edited January 2012
    Sokurah wrote: »
    If I was a manager and had someone working on a game, who I found out was laying the foundation for another game or two, while still being able to finish off that first game on schedule, I'd make sure I kept the programmer employed.
    ...not all games development are a mad rush towards the end.
    I was speaking from experience, both mine and my colleagues. Without name-dropping I can point to one of my friends who was told to choose between the game he was being paid to write or the one of his own he was working on when he thought no one was around to see. I have had to pretend to be someone else when calling up a graphic artist working for me and who was also working in-house at Probe since if it was known he was moonlighting for me he'd have been sacked.

    Some managers\software houses got very proprietary about their coders and took it personally if they found out you weren't giving 100% to the game they were paying you to write - whatever the circumstances.
  • edited January 2012
    climacus wrote: »
    With a 128k is too easy... I want to do something interesting in 48k. Now I?m thinking that in a game with 10 or 15 sprites in screen perhaps dump method is the best

    Well... My first sprite routines work this way: for every sprite, I have a routine to erase it from the screen, restoring whatever it was on it before drawing the sprite. Another one to calculate off-screen the current sprite to be drawn (that is, to rotate the sprite according to the X-coordinate modulo 8 value), and another one to render the actual sprite (and at the same time, keep the screen contents I'm overwritting).

    The most CPU-consuming routine is the calculate-rotate sprite. So, my interrupt routine usually goes as follows:
    For every sprite from 1 to N
    - Erase the sprite from screen, restoring previous contents
    Next
    For every sprite from N to 1
    - Write the updated sprite on screen, keeping an off-screen buffer of its previous contents. These contents will be needed for step 1 at the next frame time.
    Next
    For every sprite from 1 to N
    - Calculate (rotate) the sprite that will need to be used at the next frame time on step 2
    Next

    Steps 1 and 2 have to be performed before the raster begins to draw the first scan of my playfield (you can gain extra time by putting your playfield at the bottom of the screen, leaving the upper part for static graphics, score, and so on). Step 3 can be performed while the raster scan is drawing the screen, as no screen operations are being performed.

    As for the rest of steps, I usually call the Vortex interrupt routine to play music, and perform colission detection.

    There's another technique I'm starting to use now, that allows me to put even more sprites. It's the well known technique of sprite compiling. If you have a 16x16 sprite available, I can show you how to use it :)
  • edited January 2012
    Turkwel wrote: »
    Some managers\software houses got very proprietary about their coders and took it personally if they found out you weren't giving 100% to the game they were paying you to write - whatever the circumstances.
    Sounds like you get a crappy deal, though it sounds like contract work to me. I'm on a salary for the company so I do what needs doing on whatever projects are current (though they're not games). And if that means loading up a truck then I get to be a 'hardware' guy for a few hours. Working on your own private project on company time would get you a nadgering for sure, but solving the problem of the guy sat opposite you or swapping tasks based on expertise rather than who your manager is playing golf with at the time seems to get everything done a lot more smoothly. It means the project managers have to earn their crust too, keeping track of it all when you hand your timesheet in.
    Joefish
    - IONIAN-GAMES.com -
  • edited January 2012
    If you have a 16x16 sprite available, I can show you how to use it :)

    help yourself to anything I've posted in this thread :smile:

    http://www.worldofspectrum.org/forums/showthread.php?t=37142
  • edited January 2012
    I've just scanned John Durst's Machine Code Sprites and Graphics for the ZX Spectrum. All 160 odd pages of it.

    It's a good book - though you may have already conquered the techniques presented it in, it is still an excellent tutorial.

    I'll ask karingal & Martijn to upload it to WOS and add links in the books section over the weekend. I'll put it on my website to for you to download.

    Edit: Uploaded http://www.zxdesign.info/docs/MachineCodeSpritesAndGraphics_en.pdf
    Size is 65Mb, and 166 pages, including cover. Enjoy.
  • edited January 2012
    csmith wrote: »
    I've just scanned John Durst's Machine Code Sprites and Graphics for the ZX Spectrum. All 160 odd pages of it.

    It's a good book - though you may have already conquered the techniques presented it in, it is still an excellent tutorial.

    I'll ask karingal & Martijn to upload it to WOS and add links in the books section over the weekend. I'll put it on my website to for you to download.

    Edit: Uploaded http://www.zxdesign.info/docs/MachineCodeSpritesAndGraphics_en.pdf
    Size is 65Mb, and 166 pages, including cover. Enjoy.
    Uploaded.
    I wanna tell you a story 'bout a woman I know...
  • edited January 2012
    Well... My first sprite routines work this way: for every sprite, I have a routine to erase it from the screen, restoring whatever it was on it before drawing the sprite. Another one to calculate off-screen the current sprite to be drawn (that is, to rotate the sprite according to the X-coordinate modulo 8 value), and another one to render the actual sprite (and at the same time, keep the screen contents I'm overwritting).

    The most CPU-consuming routine is the calculate-rotate sprite. So, my interrupt routine usually goes as follows:
    For every sprite from 1 to N
    - Erase the sprite from screen, restoring previous contents
    Next
    For every sprite from N to 1
    - Write the updated sprite on screen, keeping an off-screen buffer of its previous contents. These contents will be needed for step 1 at the next frame time.
    Next
    For every sprite from 1 to N
    - Calculate (rotate) the sprite that will need to be used at the next frame time on step 2
    Next

    Steps 1 and 2 have to be performed before the raster begins to draw the first scan of my playfield (you can gain extra time by putting your playfield at the bottom of the screen, leaving the upper part for static graphics, score, and so on). Step 3 can be performed while the raster scan is drawing the screen, as no screen operations are being performed.

    As for the rest of steps, I usually call the Vortex interrupt routine to play music, and perform colission detection.

    There's another technique I'm starting to use now, that allows me to put even more sprites. It's the well known technique of sprite compiling. If you have a 16x16 sprite available, I can show you how to use it :)

    Hi.

    Your first Sprite routine! Could you share with us your current thoughts (not code if guarded) of your current / most recent engine?

    For my thought process do you balance both the generation and the display update routines to give the best overall performance / memory usage? The reason I ask is that looking at the T-States and memory involved might lead me to a different conclusion when comparing both aspects of producing sprites than say just the print / screen update routine.

    Cheers

    Mike

    PS Not coded anything for 20 years, sprites had always been a black art which I am still getting to grips with.
  • edited January 2012
    karingal wrote: »
    Uploaded.

    Very very thanks.!!!
  • edited January 2012
    Well... My first sprite routines work this way: for every sprite, I have a routine to erase it from the screen, restoring whatever it was on it before drawing the sprite. Another one to calculate off-screen the current sprite to be drawn (that is, to rotate the sprite according to the X-coordinate modulo 8 value), and another one to render the actual sprite (and at the same time, keep the screen contents I'm overwritting).

    The most CPU-consuming routine is the calculate-rotate sprite. So, my interrupt routine usually goes as follows:
    For every sprite from 1 to N
    - Erase the sprite from screen, restoring previous contents
    Next
    For every sprite from N to 1
    - Write the updated sprite on screen, keeping an off-screen buffer of its previous contents. These contents will be needed for step 1 at the next frame time.
    Next
    For every sprite from 1 to N
    - Calculate (rotate) the sprite that will need to be used at the next frame time on step 2
    Next

    Steps 1 and 2 have to be performed before the raster begins to draw the first scan of my playfield (you can gain extra time by putting your playfield at the bottom of the screen, leaving the upper part for static graphics, score, and so on). Step 3 can be performed while the raster scan is drawing the screen, as no screen operations are being performed.

    As for the rest of steps, I usually call the Vortex interrupt routine to play music, and perform colission detection.

    There's another technique I'm starting to use now, that allows me to put even more sprites. It's the well known technique of sprite compiling. If you have a 16x16 sprite available, I can show you how to use it :)
    Very thanks!!! I supose that you aren?t using shadow screen, are you? If not, how many sprites can you manage with this technique at same time without flicking? I?d tried to do this without a buffer screen and I?d got problems with more than four. Do you use a table of pre-rotate bytes for going faster? For the other technique, tell me wich kind of graphic do you need, with mask? How do you need the mask... This can be very interesting!!!!!
  • edited January 2012
    Spiky16384 wrote: »
    ...The reason I ask is that looking at the T-States and memory involved might lead me to a different conclusion when comparing both aspects of producing sprites than say just the print / screen update routine.

    PS Not coded anything for 20 years, sprites had always been a black art which I am still getting to grips with.

    Funny how I keep hearing "Not coded for 20 years. Sprites has always been a black art"...it certainly was true for me too. :D

    I'd suggest you don't worry too much about T-states to begin with. For me it took a bit of courage to start on my first game, after reading threads here about optimising routines and seeing 10 different versions of routines doing the exact same thing, only each time the newer one was saving a couple of bytes and some T-states - "could I do something that would be acceptable at all compared to that". Turns out I could. Just start coding and then optimise as you go.
    Website: Tardis Remakes / Mostly remakes of Arcade and ZX Spectrum games.
    My games for the Spectrum: Dingo, The Speccies, The Speccies 2, Vallation, SQIJ.
    Twitter: Sokurah
  • edited January 2012
    Sokurah wrote: »
    Funny how I keep hearing "Not coded for 20 years. Sprites has always been a black art"...it certainly was true for me too. :D

    I'd suggest you don't worry too much about T-states to begin with. For me it took a bit of courage to start on my first game, after reading threads here about optimising routines and seeing 10 different versions of routines doing the exact same thing, only each time the newer one was saving a couple of bytes and some T-states - "could I do something that would be acceptable at all compared to that". Turns out I could. Just start coding and then optimise as you go.

    Well... This makes me happy. I thought that I was the only person with problems With the screen routines.
  • edited January 2012
    climacus wrote: »
    Very thanks!!! I supose that you aren?t using shadow screen, are you? If not, how many sprites can you manage with this technique at same time without flicking? I?d tried to do this without a buffer screen and I?d got problems with more than four. Do you use a table of pre-rotate bytes for going faster? For the other technique, tell me wich kind of graphic do you need, with mask? How do you need the mask... This can be very interesting!!!!!

    If speed if your thing then you will need to pre-shift the sprites. The common method is to use a look-up table - or actually 8 of them - each of 256 bytes holding the numbers 0->255 shifted by 0 in the first table, 1 in the second, 2 in the third, and so on so you have all the combinations. You would then look-up the shift of the sprite graphic, rather than doing the actual shifting each time. You can skip the first table - shift by 0 - if you like and just have a straight routine which blits the data. And if you align the tables on 256-byte boundaries you can select the table for the shift required with the high-byte, and load the low-byte with the value, and then just read the result.

    Another way is to pre-store the graphics themselves as pre-shifted. This is faster to blit, but depending on the number of graphics you are using might use more memory than the 2K required by the shift table above.
    climacus wrote: »
    Well... This makes me happy. I thought that I was the only person with problems With the screen routines.

    Everybody has problems with this when they start, but it's well worth the effort to learn all the tricks as you'll learn a lot about machine-code which can also be used in other situations. One of the best moments in my life was, as a boy of 13, getting my first sprite routine to work - it was just a black 16x16 square moving in pixel steps around the screen - but I suddenly felt that I could now take on Ultimate!
  • edited January 2012
    You know, I've just started learning and not got even anywhere near putting stuff up on the screen (I'm taking my time, see). I'm a programmer but feel a bit stupid with the term "pre-shifting" sprites...I've seen it mentioned a few time but I'm not sure I really understand what the term means, so at the expense of sounding daft, could you explain what that really means to me, please? :-?

    We should have a glossary of terms. Why didn't Penguin Books make Spectrum programming books!
  • edited January 2012
    redballoon wrote: »
    You know, I've just started learning and not got even anywhere near putting stuff up on the screen (I'm taking my time, see). I'm a programmer but feel a bit stupid with the term "pre-shifting" sprites...I've seen it mentioned a few time but I'm not sure I really understand what the term means, so at the expense of sounding daft, could you explain what that really means to me, please? :-?

    Certainly!

    First the basics - All memory is stored in Bytes - i.e. groups of eight on/off bits. The same goes for the screen, where each of those bits represents a pixel. So if you want to plot a pixel at position 0 then you set the left-most bit (bit 7), position 1 at bit 6, and so on so position 7 is bit 0 (the right-most bit). Position 8 is bit 7 in the next byte, and so.

    Sprites are usually also defined in bytes, and so if you want to draw the sprite starting at position 0 then all is good and simple - as each bit of your sprite lines up perfectly with the bits of the screen memory - but if you want to draw the sprite at positions 1 to 7 then you need to re-arrange the sprite data so that it is correct to line up with the bits of the screen memory again. This is called shifting. For position 1 you'd need to shift all the bits in your sprite 1 bit to the right, for position 2 two shifts right, up to 7 shifts right for position 7.

    All that shifting is slow, especially as you'd be doing it every frame for everything you draw on the screen. So there are two solutions to speed it up:

    1 - Use "pre-shifted" sprites where you hold eight different versions of the sprite, each shifted along from the next, so you just use the right one for the position you want to draw it. If you only draw your sprite at 2 pixel intervals you will only need 4 sprites (at positions 0, 2, 4, & 6), or at 4 pixels intervals only 2 sprites (at positions 0 & 4).

    2 - Use a table to look-up the result of calculating any number shifted by any amount, which is much quicker than performing the right amount of shifting each time. It's also a consistent amount of time - where shifting by just one bit will be faster than shifting by 7 bits.


    (Sorry to anybody if that was a bit basic - I'll not sure where everybody's level is. The above would benefit from some pictures, but I'm hoping it makes some sense as it is)
  • edited January 2012
    Pre-shifted sprites are when you have multiple copies of the sprite in memory, each one moved a little further to the right, in 1, 2 or 4 pixel steps, depending on the accuracy you want.

    Then, when you come to draw the sprite, you pick the byte position in memory to draw it, then pick the sprite that's shifted closest to the precise pixel position, and copy that one up.

    The disadvantages are that it takes more memory, for 4 or 8 copies of your sprite. Also a 16x16 sprite then requires you actually store a 24x16 sprite for each frame, to accommodate the movement.

    One advantage is that you can combine a walking/flying/rolling animation with the movement.

    Jet Set Willy is probably the most skilled demonstration of animated pre-shifting. The sprites that move left/right are pre-shifted 2 pixels at a time over 4 frames of animation. In that case you can have up to a 10x16 image and fit it within a 16x16 frame as it only needs to shift over by 0, 2, 4 or 6 pixels and stay within the frame. But there's more to it than that - some of the sprite animations actually expand as they pass through the middle of the 16x16 frame, then contract as they near the edge (Willy's walk for example, or the rolling egg, which is upright and narrow at the point the graphic moves by a whole byte).
    Joefish
    - IONIAN-GAMES.com -
  • edited January 2012
    ah, thanks Bobs and Joefish, good explanations and make things a lot clearer now. :)
  • edited January 2012
    Redballoon, before you start to think about tstates,interrupts, shadow screens, preshifting and so on try some simpler things. Draw your sprites at equal character positions and move them also by characters=8 pixels. That's really easier.

    And a lot of proffesional games works this way :)
  • edited January 2012
    Yeah, don't worry so much about doing things the "absolutely best way" from the beginning - It's okay to start out simple and then improve later on.

    The first version of the (then, so called) "sprite routine" in Dingo only moved pixelwise going up/down the first 3 weeks - when you moved left/right the sprite only moved blockwise.

    Then I rewrote it completely a couple of times before it finally worked as it should (with help from joefish, thanks).

    ...I'm sure Driller wasn't written in one go either, and I'm equally sure nobody expects you to make the most technical masterpiece as your first game either. Just get started and then improve your code as you get better.
    Website: Tardis Remakes / Mostly remakes of Arcade and ZX Spectrum games.
    My games for the Spectrum: Dingo, The Speccies, The Speccies 2, Vallation, SQIJ.
    Twitter: Sokurah
  • edited January 2012
    Sokurah wrote: »
    I'm equally sure nobody expects you to make the most technical masterpiece as your first game either.
    What? No-one told me that. I bet you only just found out, too...
    91%? F*ck off with you... :p :p :p
    Joefish
    - IONIAN-GAMES.com -
  • edited January 2012
    Sokurah wrote: »
    Funny how I keep hearing "Not coded for 20 years. Sprites has always been a black art"...it certainly was true for me too. :D

    I'd suggest you don't worry too much about T-states to begin with.

    "could I do something that would be acceptable at all compared to that". Turns out I could. Just start coding and then optimise as you go.

    Brilliant idea, on reflection I have been too wrapped up in the optimal routine and have yet to produce anything that actually works.

    Thanks

    M
  • edited January 2012
    Spiky16384 wrote: »
    Brilliant idea, on reflection I have been too wrapped up in the optimal routine and have yet to produce anything that actually works.

    I think the middle ground is best - don't go all-out for uber-optimised code, but also don't aim your sights too low because you think otherwise it'll be too difficult. Think of what you want to do, discuss if it is realistic, then go for it, otherwise you could get to the end result and think "it's nice, but what I really wanted to write was...". Per-pixel movement isn't difficult, nor does it require perfect code. The first game I wrote was Stranded, and in hindsight it sucked from a coding point-of-view, but it did what I wanted it to do, so I was very pleased when I completed it, and then allowed me to focus on improving from there. If your idea doesn't involve per-pixel movement then that's fine, but don't avoid it completely - maybe just delay it a bit as Sokurah did with Dingo.
  • edited January 2012
    apenao wrote: »
    1.- Use a dirty buffer. Instead of copying the whole screen each time, keep track of the squares that need refreshing (that's why you use a dirty buffer), making the process a lot faster. I think this is the method used in the C compiler that is around here. (z88dk iirc)

    There is a tradeoff between time needed for accounting and time needed for drawing. Once your game requires a certain minimum amount of screen redraw, it is faster to go with a method that just draws it all to screen with minimal accounting.

    Having said that, the sp1 engine is double buffering taken to its logical conclusion. It tries to gain speed versus draw-it-all methods a few ways:

    1. It keeps track of each individual character square that needs redrawing by adding 'dirtied' character squares to an internal linked list. The list of squares are redrawn all at once during the 'sp1_UpdateNow()' call. The idea is most of the screen does not need to be drawn so time is saved versus methods that redraw everything or large parts of the screen regardless of how much has actually changed from frame to frame.

    2. Dirtied character squares are only added to the list once so that they are only drawn once from frame to frame. If you print a new background character to a square, then move a new sprite over the square, sp1 will only draw the square once despite two changes having been made to the square at two different times. Most draw-it-all sprite engines will do redundant things when drawing multiple sprites that overlap in the same location. For example, a method that stores background underlying a sprite as it is drawn for restoration later will store background several times when more than one sprite occupies the same area on screen. This amounts to many wasted cpu cycles.

    3. Display addresses are never used or computed during draw operations. This is probably a bit surprising to most who read this the first time :) One difficulty when drawing sprites to screen directly is that you need registers to track the destination screen address and you need cpu cycles to compute the next screen address to draw to while copying the sprite graphic. The sp1 engine reduces the double buffer to just 8 bytes (one character) and as it draws the graphics for the character, it draws background followed by all the sprites that occupy the character into that buffer. Only when the completed character square graphic is done does it copy this to screen. All sprite and background data is therefore drawn to an 8-byte block at *fixed* address. This allows the used of absolute memory addresses in draw code or (IX+n) type addressing. When that data is copied to screen, the destination screen address is retrieved from the character square descriptor which was precomputed during initialization.

    4. No synchronization with the raster is done. This means there are no wasted cycles in a HALT, eg, waiting to synchronize screen updates with the TV raster. Because only completed graphics are copied to screen, intermediate draw results are never seen and flicker is not possible. However, tearing (or some call it shearing) is, if the TV raster happens to pass through a character square being updated by the engine. Because the amount of time spent in copying the 8-byte buffer to screen is small, tearing is not too much an issue in reality.

    5. Sprites that do not move are not redrawn. Most methods draw all sprites on screen in every update. sp1 will not redraw anything unless changes have occurred. This allows sprites to become background elements without causing cpu overhead, and allows games to stagger updates across several frames to maintain frame rate even with many sprites on screen. Eg, You may want to update the player's sprite at every screen update and if screen action is cluttered, you may want to redraw half the enemy sprites in one update and half in another to maintain frame rate.

    6. Sprites can be drawn using a selection of provided routines (masked, ORed, XORed, LOAD, etc) or even custom routines. Some types draw faster than others but they can share the same graphic data. Horizontal shifting is accomplished via table lookup but the draw routines are smart enough that a 0 horizontal shift causes a much faster blit to screen to be used.

    7. Individual sprite characters can be classed as 'occluding', meaning they cover everything underneath them. If that is the case, the engine will not draw anything underneath them.

    8. Background for each individual character square is associated with a letter (or udg if you prefer) 0-255. The engine looks up the graphic associated with the letter for drawing backgrounds. This speeds up background updates as the game only has to write one byte to cause a change to 8-bytes of screen data. Further, it is easy to accomplish large background animations using this technique. The letter A might be associated with an animated flower, for example. Simply by changing the graphic associated with the letter A, the engine can animate flowers (As) printed all over the screen in each frame. This simulates text mode displays on other computers.

    Anyway those are some of the ideas used in the sp1 engine, which is double buffering type. As should be clear there is additional accounting overhead associated with sprites so that although the actual draw code will be faster than other types of sprite engines, the overhead will overcome that advantage once there is enough going on on-screen. Also because of the screen update algorithm (character based), animating large contiguous blocks of screen will cause artifacts to be visible (ie tearing) that would not otherwise be visible using other engine types. A nice side effect is that the draw and update algorithms allow some quite neat effects that would otherwise be very difficult to accomplish using other algorithms.
  • edited January 2012
    When I code normally, i always go for efficiency and optimisation...but I'll just be happy to get 1 of my sprites on screen and moving about no matter what!
  • edited January 2012
    There is a tradeoff between time needed for accounting and time needed for drawing. Once your game requires a certain minimum amount of screen redraw, it is faster to go with a method that just draws it all to screen with minimal accounting.

    Having said that, the sp1 engine is double buffering taken to its logical conclusion. It tries to gain speed versus draw-it-all methods a few ways:

    1. It keeps track of each individual character square that needs redrawing by adding 'dirtied' character squares to an internal linked list. The list of squares are redrawn all at once during the 'sp1_UpdateNow()' call. The idea is most of the screen does not need to be drawn so time is saved versus methods that redraw everything or large parts of the screen regardless of how much has actually changed from frame to frame.

    2. Dirtied character squares are only added to the list once so that they are only drawn once from frame to frame. If you print a new background character to a square, then move a new sprite over the square, sp1 will only draw the square once despite two changes having been made to the square at two different times. Most draw-it-all sprite engines will do redundant things when drawing multiple sprites that overlap in the same location. For example, a method that stores background underlying a sprite as it is drawn for restoration later will store background several times when more than one sprite occupies the same area on screen. This amounts to many wasted cpu cycles.

    3. Display addresses are never used or computed during draw operations. This is probably a bit surprising to most who read this the first time :) One difficulty when drawing sprites to screen directly is that you need registers to track the destination screen address and you need cpu cycles to compute the next screen address to draw to while copying the sprite graphic. The sp1 engine reduces the double buffer to just 8 bytes (one character) and as it draws the graphics for the character, it draws background followed by all the sprites that occupy the character into that buffer. Only when the completed character square graphic is done does it copy this to screen. All sprite and background data is therefore drawn to an 8-byte block at *fixed* address. This allows the used of absolute memory addresses in draw code or (IX+n) type addressing. When that data is copied to screen, the destination screen address is retrieved from the character square descriptor which was precomputed during initialization.

    4. No synchronization with the raster is done. This means there are no wasted cycles in a HALT, eg, waiting to synchronize screen updates with the TV raster. Because only completed graphics are copied to screen, intermediate draw results are never seen and flicker is not possible. However, tearing (or some call it shearing) is, if the TV raster happens to pass through a character square being updated by the engine. Because the amount of time spent in copying the 8-byte buffer to screen is small, tearing is not too much an issue in reality.

    5. Sprites that do not move are not redrawn. Most methods draw all sprites on screen in every update. sp1 will not redraw anything unless changes have occurred. This allows sprites to become background elements without causing cpu overhead, and allows games to stagger updates across several frames to maintain frame rate even with many sprites on screen. Eg, You may want to update the player's sprite at every screen update and if screen action is cluttered, you may want to redraw half the enemy sprites in one update and half in another to maintain frame rate.

    6. Sprites can be drawn using a selection of provided routines (masked, ORed, XORed, LOAD, etc) or even custom routines. Some types draw faster than others but they can share the same graphic data. Horizontal shifting is accomplished via table lookup but the draw routines are smart enough that a 0 horizontal shift causes a much faster blit to screen to be used.

    7. Individual sprite characters can be classed as 'occluding', meaning they cover everything underneath them. If that is the case, the engine will not draw anything underneath them.

    8. Background for each individual character square is associated with a letter (or udg if you prefer) 0-255. The engine looks up the graphic associated with the letter for drawing backgrounds. This speeds up background updates as the game only has to write one byte to cause a change to 8-bytes of screen data. Further, it is easy to accomplish large background animations using this technique. The letter A might be associated with an animated flower, for example. Simply by changing the graphic associated with the letter A, the engine can animate flowers (As) printed all over the screen in each frame. This simulates text mode displays on other computers.

    Anyway those are some of the ideas used in the sp1 engine, which is double buffering type. As should be clear there is additional accounting overhead associated with sprites so that although the actual draw code will be faster than other types of sprite engines, the overhead will overcome that advantage once there is enough going on on-screen. Also because of the screen update algorithm (character based), animating large contiguous blocks of screen will cause artifacts to be visible (ie tearing) that would not otherwise be visible using other engine types. A nice side effect is that the draw and update algorithms allow some quite neat effects that would otherwise be very difficult to accomplish using other algorithms.

    Gulp!!!! I must study this post very very slowly.
Sign In or Register to comment.