Building Screens

The place for codemasters or beginners to talk about programming any language for the Spectrum.
Post Reply
User avatar
Hedge1970
Manic Miner
Posts: 388
Joined: Mon Feb 18, 2019 2:41 pm

Building Screens

Post by Hedge1970 »

So I am starting to at least put some of my own code together. I am wondering about the two ways shown below to do the same thing. The first is very complex (for me) in that I have to control the loops carefully making sure I have the correct conditions, then I have to use the RR sequence to move from the top third of the screen to the middle third. I also feel more in control, but adding more to each row is going to take some head scratching :lol:

The second example is very easy, just relies on simply writing out where you want stuff and almost building the screens in text in front of your very eyes as shown in the third block. I am sure there are many many benefits of the first routine, but are there real world uses for the second?

Just think of the letter a as a UDG

Hard Code (for me)

Code: Select all

;PROJECT AIMS
;
;looking to set up a screen line by line with the aim of 
;then scrolling it continuously like car track or tiger 
;heli screen etc..
;
;
			ORG 32768
			JP start
;#########################################################
;#
;#  pr_screen uses HL,BC,DE and A
;#  
;#
;#########################################################
pr_screen	PUSH HL
			LD B,#08
;loop - the address DE is a letter 8x8 so DJNZ 8 times 
;HL is screen print address start 4000,4100,4200...4800
;Then we add 32d to L DE #0020 for next line
;HL = 4020 then 4120,4220...4820 and on for 8 rows.
loop		LD A,(DE)
			LD (HL),A				;Printing to screen			
			INC H
			INC DE
			DJNZ loop
			LD DE,#0020
			POP HL
			LD A,C
;Compare to see if we are at the 8th row - before the 
;boundary If we are, we do not want to ADD as DEC C  
;will eq 0 and we do the boundary crossing code.
			CP #01
			JR Z, setChar
			ADD HL,DE
setChar		LD DE,#3F08
			DEC C
			JP NZ,pr_screen
			RET
;#
;#########################################################
;#
start		LD HL,#4000				;16384 - 22528
			LD DE,#3F08
			LD C,#08
			CALL pr_screen	
;The code below simply moves the character across 
;the 1/3rd boundary
			RR H
			RR H
			RR H
			LD BC,#0020
			ADD HL,BC
			RL H
			RL H
			RL H
;end code move
			LD DE,#3F08
			LD C,#08
			CALL pr_screen
			RET
Easy example of the above

Code: Select all

			ORG 32768
			JP start
;#########################################################
;#
;#  s_print is from a book
;#
;#########################################################
s_print		POP HL				;pulls address off stack
			LD A,(HL) 			;this refers to first byte of defm
			INC HL				;alter +1 return byte address
			PUSH HL
			AND A				;Reset Carry and Set Zero if 0
			RET Z				;when we reach defb #00 return
			RST #10 			;else print message to screen
			JR s_print
start		XOR A
			LD (#5C3C),A
			CALL s_print
			DEFM "a",#0D
			DEFM "a",#0D
			DEFM "a",#0D
			DEFM "a",#0D
			DEFM "a",#0D
			DEFM "a",#0D
			DEFM "a",#0D
			DEFM "a",#0D
			DEFM "a",#0D
			DEFM "a",#0D
			DEFM "a",#0D
			DEFM "a",#0D
			DEFM "a",#0D
			DEFM "a",#0D
			DEFM "a",#0D
			DEFM "a",#0D
			DEFB #00
			RET
Easy Extended example of above. Took seconds. Yet for me to do this in the first example will take hours of thinking.

Code: Select all

			ORG 32768
			JP start
;#########################################################
;#
;#  s_print is from a book
;#
;#########################################################
s_print		POP HL				;pulls address off stack
			LD A,(HL) 			;this refers to first byte of defm
			INC HL				;alter +1 return byte address
			PUSH HL
			AND A				;Reset Carry and Set Zero if 0
			RET Z				;when we reach defb #00 return
			RST #10 			;else print message to screen
			JR s_print
start		XOR A
			LD (#5C3C),A
			CALL s_print
			DEFM "a b c d",#0D
			DEFM "a      bcd",#0D
			DEFM "a           bcd",#0D
			DEFM "abcd",#0D
			DEFM "aaaaa",#0D
			DEFM "aaa",#0D
			DEFM "aaaaa",#0D
			DEFM "aa",#0D
			DEFM "aaaaaaa",#0D
			DEFM "aa",#0D
			DEFM "aa",#0D
			DEFM "aaaaaaaaaaaa",#0D
			DEFM "aa",#0D
			DEFM "aaaa",#0D
			DEFM "aa",#0D
			DEFM "abbbbbcccccdddddd",#0D
			DEFB #00
			RET
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2641
Joined: Mon Nov 13, 2017 3:16 pm

Re: Building Screens

Post by Ast A. Moore »

Hedge1970 wrote: Fri Feb 21, 2020 11:47 am I am sure there are many many benefits of the first routine, but are there real world uses for the second?
Here’s something to keep in mind about the Spectrum (and many other 8-bit computers of the era): it’s extremely underpowered. For this reason, there are no universal approaches to coding (i.e. “libraries”). You’ll always be better off tweaking your code to suit your particular needs. So, to answer your question, yours is a real-world use. As long as you can use it and understand how it works, it’s as good an example of real-world use as any.

Pretty soon you’ll outgrow character-based graphics and want to venture into sprites. Then, learning how the Spectrum’s screen is organized will become essential. Your book should explain it, but there are plenty more that cover the same topic. I suggest you read them all. While they explain the same subject, each author will have a different teaching approach. Some wording might work better for you than others.
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
User avatar
RMartins
Manic Miner
Posts: 776
Joined: Thu Nov 16, 2017 3:26 pm

Re: Building Screens

Post by RMartins »

Is it just me, or you forgot to give us context on what you are trying to accomplish !?

My psychic powers are low today :D
User avatar
Hedge1970
Manic Miner
Posts: 388
Joined: Mon Feb 18, 2019 2:41 pm

Re: Building Screens

Post by Hedge1970 »

RMartins wrote: Fri Feb 21, 2020 5:01 pm Is it just me, or you forgot to give us context on what you are trying to accomplish !?

My psychic powers are low today :D
Hey, thanks no you've not missed anything, :)

I've been learning Machine Code over the past few weeks and just starting to think about my own code rather than copying from the books. AST Moore has been extremely helpful and I guess followed my meandering progress on other threads.

A couple of years ago now I wrote a game in Basic (posted here) and while it was quite playable it was heavily compromised, so from that point I thought I should learn machine code. Needless to say it was harder than I thought. I was really held back by trying to use Crystals Zeus Assembler on my real Spectrum and it was very tricky to implement code from books. I have now switched to a PC based assembler - Pasmo - and a text editor which has finally allowed me to make some progress.

Been trying very hard not ask stupid questions and to learn from books but in the end some things just stump me.

I hope the above is not stupid, it may not be the best code, but its mine and I have had to think about it in order to get this far. But it struck me how much easier it was to implement using the books s_print routine and that got me thinking so I posted the general question with no real intent other than to build a game a screen in machine code.
Ast A. Moore wrote: Fri Feb 21, 2020 3:37 pm ...Pretty soon you’ll outgrow character-based graphics and want to venture into sprites. Then, learning how the Spectrum’s screen is organized will become essential. Your book should explain it, but there are plenty more that cover the same topic. I suggest you read them all. While they explain the same subject, each author will have a different teaching approach. Some wording might work better for you than others.
This answered one of my questions that was do you just build graphics on the fly or use UDGs. Thank you

While it by no means working as expected it does at least show that I can potentially just make small graphics and call them from routines :)

On with the studying

Code: Select all

;PROJECT AIMS
;
;looking to set up a screen line by line with the aim of 
;then scrolling it continuously like car track or tiger 
;heli screen etc..
;
;
			ORG 32768
			JP start
;#########################################################
;#
;#  pr_screen uses HL,BC,DE and A
;#  
;#
;#########################################################
head		DEFB %00000110
			DEFB %00111110
			DEFB %01111100
			DEFB %00110100
			DEFB %00111100
			DEFB %00111110
			DEFB %00011000
			DEFB %00111100
body		DEFB %01111110
			DEFB %01110111
			DEFB %11111011
			DEFB %11111100
			DEFB %00111110
			DEFB %01110110
			DEFB %01101110
			DEFB %01110111
pr_screen	PUSH HL
			LD B,#08
	;loop - the address DE is a letter 8x8 so DJNZ 8 times 
	;HL is screen print address start 4000,4100,4200...4800
	;Then we add 32d to L DE #0020 for next line
	;HL = 4020 then 4120,4220...4820 and on for 8 rows.
loop		LD A,(DE)
			LD (HL),A				;Printing to screen			
			INC H
			INC DE
			DJNZ loop
			LD DE,#0020
			POP HL
			LD A,C
	;Compare to see if we are at the 8th row - before the 
	;boundary If we are, we do not want to ADD as DEC C  
	;will eq 0 and we do the boundary crossing code.
			CP #01
			JR Z, setChar
			ADD HL,DE
setChar		LD DE,head
			BIT #00,C
			JR Z,next
			LD DE,body
next		DEC C
			JP NZ,pr_screen
			RET
;#
;#########################################################
;#
start		LD HL,#4000				;16384 - 22528
			LD DE,head
			LD C,#08
			CALL pr_screen	
;The code below simply moves the character across 
;the 1/3rd boundary
			RR H
			RR H
			RR H
			LD BC,#0020
			ADD HL,BC
			RL H
			RL H
			RL H
;end code move
			LD DE,head
			LD C,#08
			CALL pr_screen
			RET
User avatar
Joefish
Rick Dangerous
Posts: 2059
Joined: Tue Nov 14, 2017 10:26 am

Re: Building Screens

Post by Joefish »

You might as well stick with character-graphics (UDGs) for now. Not every game needs pixel-position sprites; that only leads to colour clash.

I think the best way to start is to draw an 8x8 character you've defined yourself with your own colour definition anywhere on the screen. So you copy 8 bytes to the pixel screen and one attribute.

From that you can expand it to draw larger objects, e.g. 16x16 pixels by drawing two bytes at a time over 16 rows. And copy four attribute bytes. you could, if you like, define your object as 4x4 characters and draw each character separately. Disadvantage: slower, Advantage: easy to clip off bits of it if they go off the screen. But then you find even your favourite games leave blank attributes (same INK and PAPER) at the edges of the screen, so if the sprite drawing over-runs a bit it's hidden by these border attributes.
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2641
Joined: Mon Nov 13, 2017 3:16 pm

Re: Building Screens

Post by Ast A. Moore »

Joefish wrote: Fri Feb 21, 2020 5:30 pm so if the sprite drawing over-runs a bit it's hidden by these border attributes.
Indeed, that’s a cheep cop-out, but quite effective. I prefer not to do that, but then taking care of the clipping (especially of the left-hand edge of the screen) is a pretty involved, non-trivial task. Visually, quite rewarding, though.
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
User avatar
Morkin
Bugaboo
Posts: 3277
Joined: Mon Nov 13, 2017 8:50 am
Location: Bristol, UK

Re: Building Screens

Post by Morkin »

Joefish wrote: Fri Feb 21, 2020 5:30 pmYou might as well stick with character-graphics (UDGs) for now. Not every game needs pixel-position sprites; that only leads to colour clash.
I'd probably agree with this, just give whatever you like a go. Printing with RST 16 (or 10 in hex) will still be extremely fast compared to BASIC.

You can always move onto bigger sprites or less-than-8-pixel movement later on.

One suggestion I'd have - although it's nice to know a bit about the Speccy screen display, don't worry too much if you don't understand the 'check if it's passing the 1/3 screen boundary' code. As long as you know what it's doing, you can use it..!

When I was trying to learn assembly I used a screen routine in the "Advanced Spectrum Machine Language" book, it's the very first 3 pages of chapter 1..(!) Anyway I read the explanation about 20 times and just couldn't quite understand what it was doing. But it didn't stop me using it as it's completely self-contained code - you just need to know the inputs/outputs.

It was a while afterwards that I did suss it out by following bit by bit what it was doing... Then, by the next day I'd forgotten it again. :lol: As far as I'm concerned if it works, I'm happy.

Thing is - I reckon if I'd decided I wasn't going to continue writing my code without fully understanding that bit of code, I probably would have given up and not learnt anything more.

The other thing I've noticed (in life in general!) is that when a technical author or code commentary uses the word "simply", it tends to mean I'm not going to understand it.. :lol:
My Speccy site: thirdharmoniser.com
llewelyn
Manic Miner
Posts: 205
Joined: Thu Feb 22, 2018 3:27 pm
Location: virginias eastern shore
Contact:

Re: Building Screens

Post by llewelyn »

Morkin said "The other thing I've noticed (in life in general!) is that when a technical author or code commentary uses the word "simply", it tends to mean I'm not going to understand it.. "

Did you ever hit the nail on the head with that remark! How much I agree with you.
User avatar
RMartins
Manic Miner
Posts: 776
Joined: Thu Nov 16, 2017 3:26 pm

Re: Building Screens

Post by RMartins »

Ast A. Moore wrote: Fri Feb 21, 2020 6:01 pm ...

Indeed, that’s a cheep cop-out, but quite effective. I prefer not to do that, but then taking care of the clipping (especially of the left-hand edge of the screen) is a pretty involved, non-trivial task. Visually, quite rewarding, though.
I wonder why you say this ?
Clipping to the left or right, is almost exactly the same.

Once you have the correct sprite (pre-shifted or after being shifted), it's just a matter of starting in the correct spot and skipping the correct amount of bytes.
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2641
Joined: Mon Nov 13, 2017 3:16 pm

Re: Building Screens

Post by Ast A. Moore »

RMartins wrote: Fri Feb 21, 2020 8:28 pm I wonder why you say this ?
Clipping to the left or right, is almost exactly the same.
Not quite. Checking for the right-hand edge clipping is trivial and inexpensive. You simply increment the low byte of the screen address and AND it with $1f. If the result is zero, you skip drawing the next bit. The same goes for testing your horizontal coordinate: assuming your origin is in the top left corner of a sprite, if incrementing it results in the carry being set, you know you’ve gone over.

The left-hand edge is trickier. First, you’ll need to figure out what to do with your horizontal coordinate. Do you want it to go negative? Then how do you distinguish it from positive coordinates of 128 and greater? Do you want it to remain at zero and only change the width of the sprite for collision detection until you’ve drawn the full width of the sprite (if it’s moving left to right) or shrink it’s width (if it’s moving right to left)? That makes collision detection more difficult to manage.

It’s much easier if you’re clipping to a window that’s narrower than the screen’s full width by at least a sprite’s width.
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
User avatar
RMartins
Manic Miner
Posts: 776
Joined: Thu Nov 16, 2017 3:26 pm

Re: Building Screens

Post by RMartins »

Ast A. Moore wrote: Fri Feb 21, 2020 9:29 pm
RMartins wrote: Fri Feb 21, 2020 8:28 pm I wonder why you say this ?
Clipping to the left or right, is almost exactly the same.
Not quite. Checking for the right-hand edge clipping is trivial and inexpensive. You simply increment the low byte of the screen address and AND it with $1f. If the result is zero, you skip drawing the next bit. The same goes for testing your horizontal coordinate: assuming your origin is in the top left corner of a sprite, if incrementing it results in the carry being set, you know you’ve gone over.

The left-hand edge is trickier. First, you’ll need to figure out what to do with your horizontal coordinate. Do you want it to go negative? Then how do you distinguish it from positive coordinates of 128 and greater? Do you want it to remain at zero and only change the width of the sprite for collision detection until you’ve drawn the full width of the sprite (if it’s moving left to right) or shrink it’s width (if it’s moving right to left)? That makes collision detection more difficult to manage.
If I'm not mistaken, all the complexity you are referring to, derives from the fact that you are trying to use a single byte (8bit = 256 combinations) variable, instead of using a 16 bit one, for your horizontal position.

Assuming 1 bit shifted sprites across the screen, you will need all 256 possible combinations, so that's not even an option (unless you are using some sub-multiple, like: 128, 64, or 32, that would imply shifting in 2, 4 or 8 bit steps.

In My game Steel Ball, I don't have any special condition between left and right, besides testing if I'm off to the left or off to the right. I break the rendering process in 3 sections, left (clipping), center (non clipping) and right (clipping).
Each section, just informs how much to clip and calls clipping or non clipping sprite copy/draw routines.

NOTE: The size (width) of the left and right region can be changed (currently at compile time), based on the largest (widest) sprite available (being used).

I also do a small trick, which is, once I know what my screen scene offset is (my local coordinate system), I can switch to single byte vars, since I'm sure to never leave the screen area, while rendering.
So global/world processing is using 16 bit for Horizontal position, and 8 bit for vertical position.
But local screen processing/drawing uses 8 bit vars.
Ast A. Moore wrote: Fri Feb 21, 2020 9:29 pm It’s much easier if you’re clipping to a window that’s narrower than the screen’s full width by at least a sprite’s width.
Well in this case, you don't need to clip, if you fill those character borders with PAPER=INK, so that the sprites become invisible.
But this can become a huge waste of CPU and video memory accesses, and doesn't work that great when you have variable sprite widths.
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2641
Joined: Mon Nov 13, 2017 3:16 pm

Re: Building Screens

Post by Ast A. Moore »

RMartins wrote: Sat Feb 22, 2020 3:53 pm If I'm not mistaken, all the complexity you are referring to, derives from the fact that you are trying to use a single byte (8bit = 256 combinations) variable, instead of using a 16 bit one, for your horizontal position.
Correct. But I actually refer to using fractional coordinates, so they are effectively 16-bit values (the fraction is stored in the lower byte). Your method will, or course, work, but the coordinates will effectively need to be 24 bits wide, and collision detection becomes much more unwieldy. In fact, everything becomes slower and more complex. As you say, once the sprite is within the visible screen area, you can revert to 8-bit coordinates, but that doesn’t make keeping track of everything any easier.
RMartins wrote: Sat Feb 22, 2020 3:53 pmIn My game Steel Ball, I don't have any special condition between left and right, besides testing if I'm off to the left or off to the right. I break the rendering process in 3 sections, left (clipping), center (non clipping) and right (clipping).
Each section, just informs how much to clip and calls clipping or non clipping sprite copy/draw routines.
That looks like a cute little game! The Sinclair joystick is not working, though, and the graphics are a bit glitchy. :oops:
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
User avatar
RMartins
Manic Miner
Posts: 776
Joined: Thu Nov 16, 2017 3:26 pm

Re: Building Screens

Post by RMartins »

Ast A. Moore wrote: Sat Feb 22, 2020 5:56 pm
RMartins wrote: Sat Feb 22, 2020 3:53 pm If I'm not mistaken, all the complexity you are referring to, derives from the fact that you are trying to use a single byte (8bit = 256 combinations) variable, instead of using a 16 bit one, for your horizontal position.
Correct. But I actually refer to using fractional coordinates, so they are effectively 16-bit values (the fraction is stored in the lower byte). Your method will, or course, work, but the coordinates will effectively need to be 24 bits wide, and collision detection becomes much more unwieldy. In fact, everything becomes slower and more complex. As you say, once the sprite is within the visible screen area, you can revert to 8-bit coordinates, but that doesn’t make keeping track of everything any easier.
Well, I didn't have any problems with collision detection, but my collisions were simple boxes, so I might have hacked something to make it simple.
Ast A. Moore wrote: Sat Feb 22, 2020 5:56 pm
RMartins wrote: Sat Feb 22, 2020 3:53 pmIn My game Steel Ball, I don't have any special condition between left and right, besides testing if I'm off to the left or off to the right. I break the rendering process in 3 sections, left (clipping), center (non clipping) and right (clipping).
Each section, just informs how much to clip and calls clipping or non clipping sprite copy/draw routines.
That looks like a cute little game! The Sinclair joystick is not working, though, and the graphics are a bit glitchy. :oops:
I thought you already new this one, I was just mentioning it as a reference.
You can see the [url=ZXhttps://zx-dev-2015.proboards.com/thread/18/steel-ball]Steel Ball development thread @ ZX-Dev 2015[/url].

Regarding the Sinclair joystick not working, every joystick type I know of is implemented, but you can not select them, because I did not finish the menu selection part.

Still need to finish it has initially intended.
I'm glad you liked it.

Currently it's hardcoded for QAOP.

I could provide pokes to swap the input to the correct joystick driver function.
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2641
Joined: Mon Nov 13, 2017 3:16 pm

Re: Building Screens

Post by Ast A. Moore »

RMartins wrote: Mon Feb 24, 2020 1:48 pm I did not finish the menu selection part.
Currently it's hardcoded for QAOP.
I could provide pokes to swap the input to the correct joystick driver function.
No, that’s okay, thanks. I’m probably the only Spectrum user on the planet who hasn’t gotten used to the QAOP keys. :D
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Post Reply