Displaying my first sprite

Show us what you're working on, (preferably with screenshots).
Freespirit
Microbot
Posts: 105
Joined: Wed Jul 01, 2020 2:33 pm

Displaying my first sprite

Post by Freespirit »

Thanks to R-Tape for helping with the sprite routine.


Image
Freespirit
Microbot
Posts: 105
Joined: Wed Jul 01, 2020 2:33 pm

Re: Displaying my first sprite

Post by Freespirit »

Displaying my first bit of colour on the spectrum using zx paintbrush. I had to re-code the starfield as i was just rotating the bits along the whole line where there was a star. This messed up my astronaut (arnie). Each star is now tracked. I also lost a lot of time where my code wasn't matching what was on screen while debugging lines of code, i didn't think about the raster hadn't drawn it yet, adding 'halt' helped. Next, i will see how to detect a key and move arnie left and right to start with.


Image
dfzx
Manic Miner
Posts: 682
Joined: Mon Nov 13, 2017 6:55 pm
Location: New Forest, UK
Contact:

Re: Displaying my first sprite

Post by dfzx »

Are you starting to keep track of your T state counts yet?

You'll find as you add more things to the loop you'll start coming up against the limits of the hardware. Then it gets interesting. :)
Derek Fountain, author of the ZX Spectrum C Programmer's Getting Started Guide and various open source games, hardware and other projects, including an IF1 and ZX Microdrive emulator.
Freespirit
Microbot
Posts: 105
Joined: Wed Jul 01, 2020 2:33 pm

Re: Displaying my first sprite

Post by Freespirit »

To be honest I don’t know what T state is :oops: something else I’ll need to look up. :D I can imagine my noob coding is already making the emulator work twice as hard as it needs to, so one more sprite on screen should bring it to its knees :D
dfzx
Manic Miner
Posts: 682
Joined: Mon Nov 13, 2017 6:55 pm
Location: New Forest, UK
Contact:

Re: Displaying my first sprite

Post by dfzx »

Freespirit wrote: Fri Jul 10, 2020 2:13 pm To be honest I don’t know what T state is :oops: something else I’ll need to look up. :D I can imagine my noob coding is already making the emulator work twice as hard as it needs to, so one more sprite on screen should bring it to its knees :D
Simplifying, a T state is a "tick" of the Z80 CPU. The Z80 in the Spectrum "ticks" at 3.5MHz, so you get about 3.5 million "ticks" per second. Each of your Z80 machine code instructions takes a defined number of T states, as described in the Z80 user's manual. 4 T states for a simple instruction is common, 8 or 10, or maybe more for the more complex Z80 instructions. As you build your code, adding more and more Z80 instructions to your program, it'll take more and more T states to execute (which is fine because it's doing more). Only, you'll soon get to the point when you'll start to see the limitations of what the hardware can do. You'll get flickering, or unresponsive gameplay, or whatever. At which point you'll start taking an interest in what you've got the Z80 doing, how many T states it's all taking, how you can optimise it to take less, etc.

I was being facetious. :twisted: You're doing brilliantly, and you've got a way to go yet before you need to start worrying about T states. You'll know when you do, and when you get there you'll know where to ask for help. :D
Derek Fountain, author of the ZX Spectrum C Programmer's Getting Started Guide and various open source games, hardware and other projects, including an IF1 and ZX Microdrive emulator.
Freespirit
Microbot
Posts: 105
Joined: Wed Jul 01, 2020 2:33 pm

Re: Displaying my first sprite

Post by Freespirit »

Very interesting, thanks for the info. Every little saving helps. It’s amazing to see what people can squeeze out of the spectrum, it makes it look like a computer with 10 times the speed.
User avatar
R-Tape
Site Admin
Posts: 6406
Joined: Thu Nov 09, 2017 11:46 am

Re: Displaying my first sprite

Post by R-Tape »

Great to see this. Hope it turns into a finished game.

Another way to time your code is to use the rough and ready approach of changing the border colour after each subroutine. The following picture shows the included code in action. The HALT waits for the TV raster to start drawing at the very top of the screen (this includes drawing the border), and the thickness of the colour band varies depending how long the subroutine takes. So say the blue routine was 'delete several sprites', and red was 'draw several sprites', you wouldn't be able to draw the first sprite in the top blue area, as the TV raster has already passed.

Image

Code: Select all

org 32768
main:	halt
	ld a,1
	out (254),a
	call blueroutine
	ld a,2
	out (254),a
	call redroutine
	ld a,3
	out (254),a
	call magentaroutine
	ld a,4
	out (254),a
	call greenroutine
	ld a,7
	out (254),a
	jr main
	;
blueroutine:
	ld bc,800
	call delayloop
	ret
	;
redroutine:
	ld bc,600
	call delayloop
	ret
	;
magentaroutine:
	ld bc,400
	call delayloop
	ret
	;
greenroutine:
	ld bc,200
	call delayloop
	ret
	;
delayloop:	;arrive BC holding length
	dec bc
	ld a,b
	or c
	jr nz,delayloop
	ret
	;
	
dfzx wrote: Fri Jul 10, 2020 3:56 pm You're doing brilliantly, and you've got a way to go yet before you need to start worrying about T states. You'll know when you do, and when you get there you'll know where to ask for help. :D
But also, this! Maybe don't worry about my ramblings if it doesn't have relevance yet.
Freespirit
Microbot
Posts: 105
Joined: Wed Jul 01, 2020 2:33 pm

Re: Displaying my first sprite

Post by Freespirit »

Thanks R-Tape, I was wondering of the easiest way see how much time my code was taking. This will be useful.
User avatar
cmal
Manic Miner
Posts: 630
Joined: Fri Jun 05, 2020 1:05 am
Location: California

Re: Displaying my first sprite

Post by cmal »

Great progress with the sprite routine! I like the stars effect. And thanks R-Tape for that border technique. I never thought of doing it that way. I use the old fashioned stopwatch method.
Freespirit
Microbot
Posts: 105
Joined: Wed Jul 01, 2020 2:33 pm

Re: Displaying my first sprite

Post by Freespirit »

Added a key press to move him up and when no key pressed he moves down, i might need a way to make it look smoother like gravity is affecting him when moving up. A bit like Jetpac. I'll look into that next.


Image
Freespirit
Microbot
Posts: 105
Joined: Wed Jul 01, 2020 2:33 pm

Re: Displaying my first sprite

Post by Freespirit »

My first enemy. Not very aggressive or difficult, but i have something moving so its a start. Added a basic score and a mini Arnie at the bottom who moves along as you progress the level. No idea what the game will be yet other than very simple :D


Image
Freespirit
Microbot
Posts: 105
Joined: Wed Jul 01, 2020 2:33 pm

Re: Displaying my first sprite

Post by Freespirit »

I forgot to ask, the only issue i've seen so far is sometimes when the game starts Arnie moves up and down like a key is being pressed. If i press up it still works fine. it doesn't happen everytime i start the game. Do i need to clear out the port or carry flag or something before reading it? This is the code i use to detect a key.

Code: Select all

ld bc,57342
in a,(c)
rra
call nc,moveup
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2641
Joined: Mon Nov 13, 2017 3:16 pm

Re: Displaying my first sprite

Post by Ast A. Moore »

Your keyboard polling routine is fine. It’s hard to tell without looking at the entire code, but it could be some stray value in your movement subroutine. You could use RZX to record the game and then single-step through your code in the debugger.
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
Joefish
Rick Dangerous
Posts: 2058
Joined: Tue Nov 14, 2017 10:26 am

Re: Displaying my first sprite

Post by Joefish »

Easy way to simulate a bit of gravity is to have a 'velocity' variable and apply acceleration to it.
The way it works is you have a 'vertical velocity' variable 'V' which you repeatedly add to the vertical position 'Y'. When V=0, Y doesn't change, so you hover.
Now to make something fall, you increase V. When V=1, Y increases by 1 every frame and so your sprite starts to move down. As V gets bigger, so your sprite moves down faster and faster, like it's falling, accelerating due to gravity. You should probably set an upper limit for V so it stops increasing after a while.

To make something go up (i.e. when you hold the 'fly' button down), you decrease V. That slows your fall, and eventually V turns negative and your sprite starts to move up instead. Again, you'll want to set a lower limit for V as well, to stop you shooting off the top of the screen.

You can even rebound off the top or bottom of the screen by checking Y against the screen edge. If you go off the screen edge, reset Y to just on the screen, and reverse (negate) V. Your sprite will instantly change direction like it's rebounded off a hard surface.

Now some trickier notes, if you weren't aware of using 8-bit negative numbers. 8-bit numbers go from 0-255. But they wrap-around. If you do 1+255 you get 0. But look at what that means: if you ADD 255 you've effectively SUBTRACTED 1. So in 8-bits, '255' is the same as '-1'. By extension, 254=-2, 253=-3, 252=-4 etc. So you can treat numbers 0-127 as positive and 255 down to 128 as negative numbers. So that's how our value for V can be positive or negative.

You may find you need to limit V to just -4 to +4 anyway, so your sprite doesn't move too fast.

But there's also an easy way of doing fractions with the Z80 registers too, so you can have a V or Y that works in half or quarter or even smaller fractions of a pixel.
The way you do that is to use a 16-bit number for V and Y. The Z80 can INC and DEC 16-bit numbers and ADD two of them together. So do all the above maths with 16-bit numbers. Then for your sprite position, you just take the top 8 bits as the whole number part. The lower 8 bits is your fraction (in two-hundred-and-fifty-sixths of the whole part). So now you can calculate movement and velocity in fractions.

That's quite a bit to take in, but if you want to model things like gravity and inertia you have to be able to do fractions and the like.
Freespirit
Microbot
Posts: 105
Joined: Wed Jul 01, 2020 2:33 pm

Re: Displaying my first sprite

Post by Freespirit »

Ast A. Moore wrote: Wed Jul 15, 2020 12:24 pm Your keyboard polling routine is fine. It’s hard to tell without looking at the entire code, but it could be some stray value in your movement subroutine. You could use RZX to record the game and then single-step through your code in the debugger.
Thanks for confirming the code, i can look elsewhere for the bug.
Freespirit
Microbot
Posts: 105
Joined: Wed Jul 01, 2020 2:33 pm

Re: Displaying my first sprite

Post by Freespirit »

Joefish wrote: Wed Jul 15, 2020 12:27 pm Easy way to simulate a bit of gravity is to have a 'velocity' variable and apply acceleration to it.
The way it works is you have a 'vertical velocity' variable 'V' which you repeatedly add to the vertical position 'Y'. When V=0, Y doesn't change, so you hover.
Now to make something fall, you increase V. When V=1, Y increases by 1 every frame and so your sprite starts to move down. As V gets bigger, so your sprite moves down faster and faster, like it's falling, accelerating due to gravity. You should probably set an upper limit for V so it stops increasing after a while.

To make something go up (i.e. when you hold the 'fly' button down), you decrease V. That slows your fall, and eventually V turns negative and your sprite starts to move up instead. Again, you'll want to set a lower limit for V as well, to stop you shooting off the top of the screen.

You can even rebound off the top or bottom of the screen by checking Y against the screen edge. If you go off the screen edge, reset Y to just on the screen, and reverse (negate) V. Your sprite will instantly change direction like it's rebounded off a hard surface.

Now some trickier notes, if you weren't aware of using 8-bit negative numbers. 8-bit numbers go from 0-255. But they wrap-around. If you do 1+255 you get 0. But look at what that means: if you ADD 255 you've effectively SUBTRACTED 1. So in 8-bits, '255' is the same as '-1'. By extension, 254=-2, 253=-3, 252=-4 etc. So you can treat numbers 0-127 as positive and 255 down to 128 as negative numbers. So that's how our value for V can be positive or negative.

You may find you need to limit V to just -4 to +4 anyway, so your sprite doesn't move too fast.

But there's also an easy way of doing fractions with the Z80 registers too, so you can have a V or Y that works in half or quarter or even smaller fractions of a pixel.
The way you do that is to use a 16-bit number for V and Y. The Z80 can INC and DEC 16-bit numbers and ADD two of them together. So do all the above maths with 16-bit numbers. Then for your sprite position, you just take the top 8 bits as the whole number part. The lower 8 bits is your fraction (in two-hundred-and-fifty-sixths of the whole part). So now you can calculate movement and velocity in fractions.

That's quite a bit to take in, but if you want to model things like gravity and inertia you have to be able to do fractions and the like.

Wow, Great post Joefish, many thanks. So much valuable info. I was only thinking the other day about negative numbers, i had no idea how that was going to work. I was also thinking i really need fractions of a pixel, but just thought it wasnt possible. I was blind now i can see :D
User avatar
Joefish
Rick Dangerous
Posts: 2058
Joined: Tue Nov 14, 2017 10:26 am

Re: Displaying my first sprite

Post by Joefish »

Freespirit wrote: Wed Jul 15, 2020 2:27 pm Wow, Great post Joefish, many thanks. So much valuable info. I was only thinking the other day about negative numbers, i had no idea how that was going to work. I was also thinking i really need fractions of a pixel, but just thought it wasnt possible. I was blind now i can see :D
Note that when you add 16-bit numbers, you can only add BC and DE onto HL. But that means you can also add BC or DE onto IX or IY as well, if you've got round to using those. And you can quickly EX DE,HL if you want to add BC to DE instead. e.g:
EX DE,HL
ADD HL,BC
EX DE,HL
ADD HL,DE
will first add BC onto DE, then add DE onto HL. So that's your acceleration (BC), velocity (DE) and position (HL) calculation done.

Most compilers will let you simply write in negative numbers, e.g. LD A,-1 or LD BC,-999 and they'll work out the complementary negative value for you. ADD A,-1 will do the same as SUB 1. Note that if you have an 8-bit number you're treating as 'signed', to extend it to a 16-bit number you have to sign-extend it. That is, fill the upper 8 bits with 0s for positive or 1s for negative. What you need to do is flood the upper 8 bits with a copy of the top bit of your 8-bit number, and here's a trick to do it. This sign-extends 'A' into 16 bits in 'BC':
LD C,A ; bottom 8 bits are the same as A
ADD A,A ; doubling A bumps its top bit into the CARRY flag
SBC A,A ; subtracting A from A gives you 0. Subtracting the CARRY flag on top of that gives you either 0s or all 1s (255)
LD B,A ; B is thus a whole byte of sign-extension

However, if you're using the 'fixed-decimal' method of fractions I described then if A is a whole number and you want to extend it downward by 8 bits to give it a fractional part, just set B to A and C to 0.

Also note that when you use ADD, the CARRY bit is set if the result overflows. If you then use ADC it will do an ADD, but also add-on the current carry bit. That lets you daisy-chain the adding of bigger numbers like 24-bits or 32-bits.
With 16-bit maths there is no SUB instruction, only SBC, so remember to wipe the carry bit first with a 'neutral' instruction like AND A before doing a 16-bit SBC. But it's often easier just to ADD a negative number than worry about SBC.
User avatar
Morkin
Bugaboo
Posts: 3274
Joined: Mon Nov 13, 2017 8:50 am
Location: Bristol, UK

Re: Displaying my first sprite

Post by Morkin »

Freespirit wrote: Wed Jul 15, 2020 2:18 pmThanks for confirming the code, i can look elsewhere for the bug.
My catchall was to stick an "XOR A" in front of anything like this. It usually fixes about 80% of bugs in my code without me having to do any debugging... :lol:
My Speccy site: thirdharmoniser.com
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2641
Joined: Mon Nov 13, 2017 3:16 pm

Re: Displaying my first sprite

Post by Ast A. Moore »

Joefish wrote: Wed Jul 15, 2020 4:31 pm But it's often easier just to ADD a negative number than worry about SBC.
Not only that, it’s a hell of a lot faster to boot. Well, four T states faster, to be exact, but you know, it adds up. :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.
User avatar
stupidget
Dynamite Dan
Posts: 1640
Joined: Wed Jan 24, 2018 2:09 pm
Location: Sunny Wolverhampton

Re: Displaying my first sprite

Post by stupidget »

If I had a hat I’d doff it to you [mention]Freespirit[/mention] this is an amazing job.

I wish I’d spent more time reading the spectrum BASIC book as a kid. I think I have one of those minds that simply can’t understand programming :oops:
User avatar
Pegaz
Dynamite Dan
Posts: 1210
Joined: Mon Nov 13, 2017 1:44 pm

Re: Displaying my first sprite

Post by Pegaz »

Freespirit wrote: Wed Jul 15, 2020 10:27 am My first enemy. Not very aggressive or difficult, but i have something moving so its a start. Added a basic score and a mini Arnie at the bottom who moves along as you progress the level. No idea what the game will be yet other than very simple :D


Image
If you continue to progress like this, we won’t have to wait long for a new Sidewize. :)
Freespirit
Microbot
Posts: 105
Joined: Wed Jul 01, 2020 2:33 pm

Re: Displaying my first sprite

Post by Freespirit »

Joefish wrote: Wed Jul 15, 2020 4:31 pm
Freespirit wrote: Wed Jul 15, 2020 2:27 pm Wow, Great post Joefish, many thanks. So much valuable info. I was only thinking the other day about negative numbers, i had no idea how that was going to work. I was also thinking i really need fractions of a pixel, but just thought it wasnt possible. I was blind now i can see :D
Note that when you add 16-bit numbers, you can only add BC and DE onto HL. But that means you can also add BC or DE onto IX or IY as well, if you've got round to using those. And you can quickly EX DE,HL if you want to add BC to DE instead. e.g:
EX DE,HL
ADD HL,BC
EX DE,HL
ADD HL,DE
will first add BC onto DE, then add DE onto HL. So that's your acceleration (BC), velocity (DE) and position (HL) calculation done.

Most compilers will let you simply write in negative numbers, e.g. LD A,-1 or LD BC,-999 and they'll work out the complementary negative value for you. ADD A,-1 will do the same as SUB 1. Note that if you have an 8-bit number you're treating as 'signed', to extend it to a 16-bit number you have to sign-extend it. That is, fill the upper 8 bits with 0s for positive or 1s for negative. What you need to do is flood the upper 8 bits with a copy of the top bit of your 8-bit number, and here's a trick to do it. This sign-extends 'A' into 16 bits in 'BC':
LD C,A ; bottom 8 bits are the same as A
ADD A,A ; doubling A bumps its top bit into the CARRY flag
SBC A,A ; subtracting A from A gives you 0. Subtracting the CARRY flag on top of that gives you either 0s or all 1s (255)
LD B,A ; B is thus a whole byte of sign-extension

However, if you're using the 'fixed-decimal' method of fractions I described then if A is a whole number and you want to extend it downward by 8 bits to give it a fractional part, just set B to A and C to 0.

Also note that when you use ADD, the CARRY bit is set if the result overflows. If you then use ADC it will do an ADD, but also add-on the current carry bit. That lets you daisy-chain the adding of bigger numbers like 24-bits or 32-bits.
With 16-bit maths there is no SUB instruction, only SBC, so remember to wipe the carry bit first with a 'neutral' instruction like AND A before doing a 16-bit SBC. But it's often easier just to ADD a negative number than worry about SBC.
Thanks Joefish, i just started using IX a few days ago, very handy. I didn't know about the ld a,-1 i just tried it and it compiles fine. Interesting. I will have to go through some examples and your explanation to get my head around the calculations. Its amazing all the little tricks you can do.
Freespirit
Microbot
Posts: 105
Joined: Wed Jul 01, 2020 2:33 pm

Re: Displaying my first sprite

Post by Freespirit »

stupidget wrote: Wed Jul 15, 2020 8:11 pm If I had a hat I’d doff it to you @Freespirit this is an amazing job.

I wish I’d spent more time reading the spectrum BASIC book as a kid. I think I have one of those minds that simply can’t understand programming :oops:
If i can do it anyone can! I spent a lot of time programming in Basic as a kid. It's like anything, just start off small like printing a character on screen and work your way up. It's not difficult. Unlike finding a copy of Mire Mare, that's difficult! :D
Freespirit
Microbot
Posts: 105
Joined: Wed Jul 01, 2020 2:33 pm

Re: Displaying my first sprite

Post by Freespirit »

Pegaz wrote: Wed Jul 15, 2020 8:24 pm If you continue to progress like this, we won’t have to wait long for a new Sidewize. :)
I'd not heard of this one, had to look it up. Looks good. A standard to aim for.
User avatar
Joefish
Rick Dangerous
Posts: 2058
Joined: Tue Nov 14, 2017 10:26 am

Re: Displaying my first sprite

Post by Joefish »

Freespirit wrote: Thu Jul 16, 2020 9:47 am Thanks Joefish, i just started using IX a few days ago, very handy. I didn't know about the ld a,-1 i just tried it and it compiles fine. Interesting. I will have to go through some examples and your explanation to get my head around the calculations. Its amazing all the little tricks you can do.
Yep, IX and IY are interesting. Their operations run a bit slower than the HL equivalents so most people start to use them when they run out of other registers. It's kind of a hidden feature of the Z80 but most compilers will let you use instructions that address 8-bit halves of IX and IY. So most things you can do with H and L separately, you can also do with IXH, IXL, IYH and IYL, e.g. LD IXL,1

They're also good for looking things up in a table. Like in my Pac-Man maze generator I can point IY at a cell in the table, then use LD A,(IY+1) to read the cell to the right, or (IY-32) to read the cell above.

And for structured data; for example, if your sprite data is always "1 byte for sprite ID, 1 for X, 1 for Y, 1 for Vx, 1 for Vy and 1 for HP remaining" then you can point IX at the first byte, then read (for example) the hit-points remaining on your sprite with LD A,(IX+5). That way all your functions that deal with sprites just need to be given that root IX value and they all know how to fetch the relevant data to do anything with any sprite.
Post Reply