I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
So I'm trying a fast 8 way scrolling engine only using the attribute layer for the 48k. It scrolls at 4x left and right, an 8 vertical.
I'm going to have 2 maps, one for each 4bit shift attribute.
So all the ASM has to do is read the section of the map to the attribute screen and like magic it will 'scroll'.
It's been a long time since I wrote anything in ASM, and I want to modify this to deal with it as it'll be too slow in C:
org 0x5ccb ; start of code
LD A,1
LD B,8 ; Number of times to loop (8 bits)
scroll
ld de,0x4000 ; DE = screen
LD B,A
LOOP:
inc DE
DJNZ LOOP ; Decrease B, and loop A times
inc a
Start
ld hl,ImgData ; HL = image data
ld bc,0x1aff ; 6144 bytes bitmap, 768 bytes attributes ldir counts this down until 0
ldir ; Repeats LDI (LD (DE),(HL), then increments DE, HL, and decrements BC) until BC=0. Note that if BC=0 before this instruction is called, it will loop around until BC=0 again.
;Loop
jp scroll ; infinite loop
ImgData ; data file
incbin "themap.bin"
org 0xff57
defb 00h ; end of ROM
Is this a good starting point? Is the way I'm increasing DE wrong? I've done a little loop... I need to unnderstand how to put C variables in to ASM code really.
Here is a picture of the layout of the screen to get an idea what I'm doing, all the scrolling is done by manipulating the attribute later. The sprites are then drawn on top.
I'm going to have 2 maps, one for each 4bit shift attribute.
So all the ASM has to do is read the section of the map to the attribute screen and like magic it will 'scroll'.
It's been a long time since I wrote anything in ASM, and I want to modify this to deal with it as it'll be too slow in C:
org 0x5ccb ; start of code
LD A,1
LD B,8 ; Number of times to loop (8 bits)
scroll
ld de,0x4000 ; DE = screen
LD B,A
LOOP:
inc DE
DJNZ LOOP ; Decrease B, and loop A times
inc a
Start
ld hl,ImgData ; HL = image data
ld bc,0x1aff ; 6144 bytes bitmap, 768 bytes attributes ldir counts this down until 0
ldir ; Repeats LDI (LD (DE),(HL), then increments DE, HL, and decrements BC) until BC=0. Note that if BC=0 before this instruction is called, it will loop around until BC=0 again.
;Loop
jp scroll ; infinite loop
ImgData ; data file
incbin "themap.bin"
org 0xff57
defb 00h ; end of ROM
Is this a good starting point? Is the way I'm increasing DE wrong? I've done a little loop... I need to unnderstand how to put C variables in to ASM code really.
Here is a picture of the layout of the screen to get an idea what I'm doing, all the scrolling is done by manipulating the attribute later. The sprites are then drawn on top.
Re: I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
It's a bit hard to follow what you're actually trying to do.
I'd have expected:
LD HL, 8
ADD HL, DE
EX HL,DE
would be faster than looping 8 times incrementing DE.
BUT why is DE incrementing anyway? Surely as you scroll the attributes your source pointer would change (i.e. the value in HL) but the destination (the screen attributes) would remain constant?
Maybe I've just not had enough coffee yet....
I'd have expected:
LD HL, 8
ADD HL, DE
EX HL,DE
would be faster than looping 8 times incrementing DE.
BUT why is DE incrementing anyway? Surely as you scroll the attributes your source pointer would change (i.e. the value in HL) but the destination (the screen attributes) would remain constant?
Maybe I've just not had enough coffee yet....
Re: I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
I guess you're trying to implement vertical attribute scrolling but your code is pretty incomprehensible.
It's been also some time since I've written assembler routines for the Spectrum but this could be a starting point without any optimisations.
It's been also some time since I've written assembler routines for the Spectrum but this could be a starting point without any optimisations.
Code: Select all
; Scroll up
ld bc, 0x2e0 ; size of the attribute map minus one line
ld hl, 0x5820 ; start of second line of attribute map
ld de, 0x5800 ; start of the attribute map
ldir
Code: Select all
; Scroll down
ld bc, 0x2e0 ; size of the attribute line minus one line
ld hl, 0x5adf ; end of attribute map minus one line
ld de, 0x5aff ; end of attribute map
lddr
- Einar Saukas
- Bugaboo
- Posts: 3146
- Joined: Wed Nov 15, 2017 2:48 pm
Re: I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
Unrolled loops is an easy way to improve performance. For instance, instead of this:
you can use this:
or if you want to skip a column on each side:
Code: Select all
; Scroll up
ld bc, 0x2e0 ; size of the attribute map minus one line
ld hl, 0x5820 ; start of second line of attribute map
ld de, 0x5800 ; start of the attribute map
ldir
Code: Select all
; Scroll up
ld bc, 23*256+736 ; 23 rows + 736 LDIs
ld hl, 0x5820 ; start of second line of attribute map
ld de, 0x5800 ; start of the attribute map
loop:
REPT 32
ldi
ENDR
djnz loop
Code: Select all
; Scroll up
ld bc, 23*256+736 ; 23 rows + 690 LDIs
ld hl, 0x5820 ; start of second line of attribute map
ld de, 0x5800 ; start of the attribute map
loop:
inc l ; skip left side column
inc e
REPT 30
ldi
ENDR
inc hl ; skip right side column
inc de
djnz loop
Last edited by Einar Saukas on Wed Jan 31, 2024 12:03 pm, edited 1 time in total.
- Einar Saukas
- Bugaboo
- Posts: 3146
- Joined: Wed Nov 15, 2017 2:48 pm
Re: I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
Thus basically you fill the screen with CHR$ 133 (or CHR$ 138) and your scenery will be mostly scrolling attributes, correct?
However... whenever you move left or right, you need to copy all attributes from one of your alternate maps. So why do you need to scroll anything? Is it not enough to simply copy attributes from a different part of the map to the screen?
Last edited by Einar Saukas on Wed Jan 31, 2024 11:59 am, edited 1 time in total.
Re: I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
Sounds complicated - far easier just to have two buffers and swap between them, and scroll each one a byte at a time.
Now, if you really want to be clever, write the data to the two screens of a 128K Spectrum and time it such that it takes four scanlines to update each row, and then swap screens every half character row, thus doubling the vertical attribute resolution and letting you scroll by 4 pixels vertically. Simples!
Now, if you really want to be clever, write the data to the two screens of a 128K Spectrum and time it such that it takes four scanlines to update each row, and then swap screens every half character row, thus doubling the vertical attribute resolution and letting you scroll by 4 pixels vertically. Simples!
Re: I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
I've uploaded a demo of this working, it's absurdly fast and this is with a wait VBL.
https://toastyfox.com/zx/sonic.html
Will keep you updated thank you for all the ideas, I feel 'Super Sonic Bro' might be coming sooner than I thought
https://toastyfox.com/zx/sonic.html
Will keep you updated thank you for all the ideas, I feel 'Super Sonic Bro' might be coming sooner than I thought
Re: I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
Have you looked at Ringo? https://spectrumcomputing.co.uk/entry/3 ... trum/Ringo
Source code available on GitHub https://github.com/DenisGrachev/Ringo-8
Source code available on GitHub https://github.com/DenisGrachev/Ringo-8
- ParadigmShifter
- Manic Miner
- Posts: 671
- Joined: Sat Sep 09, 2023 4:55 am
Re: I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
TLL (or Cyclone, or both) had a good optimisation where it didn't redraw any character cells which are all 1 colour (by just setting ink and paper to same value), only drawing the diagonal bits of cliffs etc. which might be worth doing (although if it is fast enough already never mind).
Re: I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
Yes, I know about Ringo, but it does not work on the 48k which is my target. It's the computer I had, and I want to push it to its limits.Stefan wrote: ↑Wed Jan 31, 2024 7:28 pm Have you looked at Ringo? https://spectrumcomputing.co.uk/entry/3 ... trum/Ringo
Source code available on GitHub https://github.com/DenisGrachev/Ringo-8
Anyhow, I now have sprites working. Using the attribute layer is damned fast, why on earth didn't more games do this back in the day...
Re: I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
True story - I'm quite friendly with Denis who wrote Ringo and before he coded it, I had a chat with him about a technique to use attributes to create a full colour low res effect. I completed a demo engine that ran on 48k. I think he must have been inspired since Ringo came out several months later, using his own methods for the 128k machine.
Anyway, long story short, I have some code which can maybe do what you want. It's timed for the 48k machine, and can read and draw attributes from a memory buffer to the screen fast enough to be synched to the beam. When it's full screen It doesn't leave a lot of time for game code, but it runs in a timed loop as the beam moves down so it can be any height. I've attached a sample picture.
Drop me a pm if you want to take a look,it would be interesting to dig it out of storage.
Anyway, long story short, I have some code which can maybe do what you want. It's timed for the 48k machine, and can read and draw attributes from a memory buffer to the screen fast enough to be synched to the beam. When it's full screen It doesn't leave a lot of time for game code, but it runs in a timed loop as the beam moves down so it can be any height. I've attached a sample picture.
Drop me a pm if you want to take a look,it would be interesting to dig it out of storage.
Re: I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
Hi,
Yes, if it can handle 50 fps or so. I've got sprites in my demo now, and you can run around the first level of Sonic, which I spent more time writing a converter for than writing the engine for this
The way I'm doing 4x8 means it takes hardly any CPU to update the screen, it's a decent trade-off but obviously Ringu on the 48k would be mind-blowing, beyond my abilities at the moment, I was told only the 128k could do it due to the ghost screen.
If you could open source your code, maybe I and everyone else could have a look at it be a real shame for something like that to be lost!
Yes, if it can handle 50 fps or so. I've got sprites in my demo now, and you can run around the first level of Sonic, which I spent more time writing a converter for than writing the engine for this
The way I'm doing 4x8 means it takes hardly any CPU to update the screen, it's a decent trade-off but obviously Ringu on the 48k would be mind-blowing, beyond my abilities at the moment, I was told only the 128k could do it due to the ghost screen.
If you could open source your code, maybe I and everyone else could have a look at it be a real shame for something like that to be lost!
Re: I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
Well, I used to open source stuff, with the strict proviso that people didn't use it for commercial games without my permission. Unfortunately this got ignored one too many times so I don't really do that anymore. But I'm always open to collaborations with like-minded chaps.
Re: I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
p.s the screen does update at 50hz. It uses an attribute buffer of 1536 bytes, with each byte containing two 3-bit colour values. Whatever you write to that buffer will be displayed on screen. But given that anything you do would have to be in the border, it's quite limiting.
Re: I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
sorry, reading that back, I don't think I was especially clear - any game code would have to be done when the raster beam was in the border, thus making it quite limited - although you could potentially use the top two thirds for the game and have quite a few more cycles to play with.
- Lethargeek
- Manic Miner
- Posts: 744
- Joined: Wed Dec 11, 2019 6:47 am
Re: I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
a bit faster method than unrolled ldis - for the each line, prepare a code like:
start: ld (hl),N: inc l: ld (hl),N ... ld (hl),N: inc l:jp start
somewhere in the middle there is a ret, you just need to shift it the each frame and replace one N value and the entry point on the stack table
for vertical scrolling you need to replace all N values for one line and correct the stack table in a similar way (with the calls to correct h in it as well)
(but it's only 14 cycles/byte vs ldi's 16 so maybe it's not worth the hassle)
start: ld (hl),N: inc l: ld (hl),N ... ld (hl),N: inc l:jp start
somewhere in the middle there is a ret, you just need to shift it the each frame and replace one N value and the entry point on the stack table
for vertical scrolling you need to replace all N values for one line and correct the stack table in a similar way (with the calls to correct h in it as well)
(but it's only 14 cycles/byte vs ldi's 16 so maybe it's not worth the hassle)
- ParadigmShifter
- Manic Miner
- Posts: 671
- Joined: Sat Sep 09, 2023 4:55 am
Re: I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
The stack is the fastest way to copy but you need to make sure no interrupts go off during the copy (so either put it inside a DI/EI section or do it straight after a HALT and make sure it does not take a whole frame to finish)
If you don't use a macro you can self modify the dest, src address before you execute it.
I also have versions which copy 14, 6 or 4 bytes for some reason. 4 byte version has HL and DE available for addresses. 6 byte version you can use HL and H'L' as src/dest address
Code: Select all
MACRO MEMCPY16 dest, src
ld sp, src
pop af
pop bc
pop de
pop hl
exx
ex af, af`
pop af
pop bc
pop de
pop hl
ld sp, dest+16
push hl
push de
push bc
push af
exx
ex af, af`
push hl
push de
push bc
push af
ENDM
I also have versions which copy 14, 6 or 4 bytes for some reason. 4 byte version has HL and DE available for addresses. 6 byte version you can use HL and H'L' as src/dest address
Code: Select all
MACRO MEMCPY14 dest, src
ld sp, src
pop af
pop bc
pop de
pop hl
exx
pop bc
pop de
pop hl
ld sp, dest+14
push hl
push de
push bc
exx
push hl
push de
push bc
push af
ENDM
MACRO MEMCPY6 dest, src
ld sp, src
pop af
pop bc
pop de
ld sp, dest+6
push de
push bc
push af
ENDM
MACRO MEMCPY4 dest, src
ld sp, src
pop af
pop bc
ld sp, dest+4
push bc
push af
ENDM
Re: I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
Thanks guys, I'm just reading up on the best way to store level data in terms of reading/writing to it (why not write to it, we have RAM after all, this isn't a console ). I apologise if I end up asking some dumb questions, I was barely alive during the spectrum era, but I love how simple the machine is.
I'm looking at the master system sonic game as a kind of inspiration, I especially like the bonus levels on that game, they seem to be the most fun part.
I'm trying to use the quirks of this engine to the Spectrums advantage in doing something a console could not, so I'm thinking maybe highly destructible levels, smashing through walls, explosions etc. etc.
I'm looking at the master system sonic game as a kind of inspiration, I especially like the bonus levels on that game, they seem to be the most fun part.
I'm trying to use the quirks of this engine to the Spectrums advantage in doing something a console could not, so I'm thinking maybe highly destructible levels, smashing through walls, explosions etc. etc.
- ParadigmShifter
- Manic Miner
- Posts: 671
- Joined: Sat Sep 09, 2023 4:55 am
Re: I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
Obviously for my fast memcpy routines you also need to save and restore SP before changing the stack pointer.
e.g. here's a fast CLS showing how to do that (also uses DI/EI)
e.g. here's a fast CLS showing how to do that (also uses DI/EI)
Code: Select all
; A -> attrib to set when clearing screen
; at exit
; HL = 0
; B = 0
cls_fast:
di ;disable interrupt
ld (.stack+1), sp ;store current stack pointer
ld sp, 16384 + 6144 + 768
ld b, 128 ; clear attribs in 128 * 3 pushes
ld h, a
ld l, a
.attribloop
push hl
push hl
push hl
djnz .attribloop
ld hl, 0
.loop1
push hl
push hl
push hl
push hl
push hl
push hl
push hl
push hl
push hl
push hl
push hl
push hl
djnz .loop1
.stack
ld sp, 0 ;parameter will be overwritten
ei
ret
Re: I'm doing a sonic clone, best way to scroll the attributes layer 4 bits at a time?
I see the demo has been updated, now there is a sprite you can control with o-p-space. Nice thing.