revision day 6

This commit is contained in:
sejo 2022-01-07 19:22:09 -06:00
parent 06cb8de530
commit 073dd3057c
1 changed files with 65 additions and 48 deletions

View File

@ -20,7 +20,7 @@ we will tackle the following elements in order:
in {uxn tutorial day 5} we discussed a way of creating a loop in order to repeat a 1bpp tile multiple times in a row.
here we will expand that procedure in order to have it repeated vertically in the whole screen.
here we will expand that procedure in order to have it also repeated vertically in the whole screen.
## setting up
@ -30,9 +30,9 @@ let's start with the following program as a template. it includes the data for a
( hello-pong.tal )
( devices )
|00 @System [ &vector $2 &pad $6 &r $2 &g $2 &b $2 ]
|20 @Screen [ &vector $2 &width $2 &height $2 &auto $1 &pad $1 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1 ]
|80 @Controller [ &vector $2 &button $1 &key $1 ]
|00 @System [ &vector $2 &pad $6 &r $2 &g $2 &b $2 ]
|20 @Screen [ &vector $2 &width $2 &height $2 &auto $1 &pad $1 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1 ]
|80 @Controller [ &vector $2 &button $1 &key $1 ]
( macros )
%RTN { JMP2r }
@ -61,7 +61,7 @@ one way would be something like:
* add 8 (the size of the tile) to x
* is x less than the limit? if it is, repeat procedure, otherwise end
### a fist version
### a first version
let's say our initial x is 0000, our width is the screen width, and the tile we are drawing is tile-background.
@ -76,7 +76,7 @@ the first step, drawing the tile in x would be:
#03 .Screen/sprite DEO ( draw 1bpp sprite with color 3 and 0 )
```
adding 8 to x, we know already:
the second step, adding 8 to x, we know already:
```
.Screen/x DEI2 #0008 ADD2 ( add 8 to x )
@ -86,8 +86,8 @@ adding 8 to x, we know already:
checking if x is less than the limit, jumping if it is, would be something like:
```
.Screen/x DEI2
.Screen/width DEI2 ( the limit )
.Screen/x DEI2 ( get x )
.Screen/width DEI2 ( get the limit )
LTH2 ,&loop JCN ( jump if x is less than the limit )
```
@ -99,14 +99,17 @@ integrating all of it, we would be able to get:
&loop-x
#03 .Screen/sprite DEO ( draw 1bpp sprite with color 3 and 0 )
.Screen/x DEI2 #0008 ADD2 DUP2 ( add 8 to x )
.Screen/x DEI2 #0008 ADD2 ( add 8 to x )
DUP2 ( duplicate new x )
.Screen/x DEO2 ( store new x )
.Screen/width DEI2 ( the limit )
.Screen/width DEI2 ( get the limit )
LTH2 ,&loop-x JCN ( jump if x is less than the limit )
```
note the use of DUP2 in order to avoid re-reading the value of x.
this should work now! but let's discuss a nicer way of doing it :)
### a second version, using the stack
instead of reading the screen width and the x coordinate each time, we could use the stack to store and manipulate those values.
@ -119,7 +122,9 @@ after setting the tile address, we can push our limit (the screen width) and the
we will be using that value at the top of the stack as the x coordinate.
inside the loop, we can duplicate it to set it as the screen x, and to increment it. in between, we can send our sprite byte in order to draw the tile.
inside the loop, we can duplicate it to set it as the screen x, and to increment it.
in between, we can send our sprite byte in order to draw the tile.
```
&loop-x
@ -170,9 +175,9 @@ the following shows our program in context, completely filling the first row of
( hello-pong.tal )
( devices )
|00 @System [ &vector $2 &pad $6 &r $2 &g $2 &b $2 ]
|20 @Screen [ &vector $2 &width $2 &height $2 &auto $1 &pad $1 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1 ]
|80 @Controller [ &vector $2 &button $1 &key $1 ]
|00 @System [ &vector $2 &pad $6 &r $2 &g $2 &b $2 ]
|20 @Screen [ &vector $2 &width $2 &height $2 &auto $1 &pad $1 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1 ]
|80 @Controller [ &vector $2 &button $1 &key $1 ]
( macros )
%RTN { JMP2r }
@ -231,7 +236,7 @@ WALL-MARGIN ( set initial y )
&loop-y
DUP2 .Screen/y DEO2 ( set y coordinate )
( draw row )
( - draw row here - )
#0008 ADD2 ( increment y )
@ -242,7 +247,7 @@ POP2 POP2 ( remove y and limit )
### nested loops
now that we have this structure, we can replace the "draw row" comment with our previous horizontal loop:
now that we have this structure, we can replace the "draw row here" comment with our previous horizontal loop:
```
;tile-background .Screen/addr DEO2 ( set tile address )
@ -318,7 +323,7 @@ nice!
in {uxn tutorial appendix a} you can find a detailed discussion of how to generalize a procedure like this one into a draw-tiles subroutine that draws an arbitrary rectangle filled with a given tile.
it goes into several possibilities for using uxntal in that abstract way: i'd say it's very interesting, but probably out of scope for making the game :)
it goes into several possibilities for using uxntal in that abstract way: i'd say it's very interesting, but it is definitely out of scope for making the game :)
# the paddles
@ -367,13 +372,13 @@ i drew the sprite using the blending mode 85 as indicated by nasu, but i will ch
let's build a subroutine that draws the 6 tiles of the paddle in the corresponding order.
we could have the subroutine receiving as argument the x and y position of its top left corner:
we could have the subroutine receiving as arguments the x and y position of its top left corner:
```
@draw-paddle ( x^ y^ -- )
```
but let's add the color byte as well:
but let's add a color byte for the sprite byte as well:
```
@draw-paddle ( x^ y^ color -- )
@ -498,7 +503,7 @@ let's reserve some space in the zero page for the x and y coordinates of each pa
we mentioned early that the x coordinate is constant; however, if we make it a variable then we can dinamically assign the x position of the paddles (especially the right one) depending on the size of the screen.
we can have a couple of macros to hold the dimensions of the paddles in order to use it later, and also its color:
we can have a couple of macros to hold the dimensions and color of the paddles in order to use them later:
```
%PADDLE-WIDTH { #0010 } ( 2 tiles )
@ -512,7 +517,7 @@ a margin to separate the paddles from the borders could be nice as well:
%MARGIN { #0010 }
```
finally, let's bring back our HALF2 macro:
finally, let's bring back our HALF2 macro from previous days:
```
%HALF2 { #01 SFT2 } ( short -- short/2 )
@ -520,7 +525,7 @@ finally, let's bring back our HALF2 macro:
### initialize positions
we can then initialize the positions of the paddles.
now we can initialize the positions of the paddles.
for the left x, we can just assign a constant value:
@ -557,7 +562,7 @@ in order to draw each paddle, we can do the following procedure inside our on-fr
### the program so far
omitting the definition of the subroutines, and as a way of having a checkpoint, right now our program would look like the following:
omitting the definition of the draw-background and draw-paddle subroutines, and as a way of having a checkpoint, right now our program would look like the following:
=> ./img/screenshot_uxn-pong-paddles.png screenshot of the two paddles, vertically centered and with the same margin relative to the sides
@ -767,15 +772,15 @@ we can define a couple of macros to refer to its parameters:
### subroutine for drawing the ball
as we'll be drawing a single ball, we can embed in its drawing subroutine the use of its own zero-page variables for the coordinates, instead of getting them as arguments in the stack.
as we'll be drawing a single ball, we can write its drawing subroutine such that it takes its coordinates from the zero-page instead of getting them as arguments in the stack.
in our zero page we can define them:
in our zero page we can define the labels for the coordinates:
```
@ball [ &x $2 &y $2 ]
```
in our setup subroutine we can assign values to them, e.g. at the middle of the screen:
and then in our setup subroutine we can assign values to them, e.g. at the middle of the screen:
```
( inside setup )
@ -789,7 +794,7 @@ HALF2
.ball/y STZ2
```
and then we can use them in our subroutine.
the coordinates are ready, so now we can use them inside our subroutine.
let's have the subroutine receive the color as an argument, so that we can clear the ball like we do with the paddles:
@ -844,7 +849,7 @@ for the movement of the ball, we'll follow the same structure as before:
* update its position
* draw the ball in the new position
it would look something like the following, and could sit along the equivalent procedures for the paddles inside the on-frame subroutine:
it would look something like the following, and it could sit along the equivalent procedures for the paddles inside the on-frame subroutine:
```
( inside on-frame )
@ -864,11 +869,11 @@ now let's discuss how to build that update-ball subroutine :)
besides our variables for keeping track of the position of the ball, we should be able to keep track of the per-axis direction it is moving.
one approach could be to have a flag for each x and y, that indicate if we should increment or decrement them.
one approach could be to have a flag for each x and y that indicates if we should increment or decrement them.
another approach could be to have a speed variable for each x and y, that gets changed according to the direction we want the ball to go.
we will use this latter approach as it will help us discuss some perks of unsigned integer arithmetic!
we will use this latter approach with the speed as it will help us discuss some perks of unsigned integer arithmetic!
we include these variables in our zero page, complementing the x and y we had already:
@ -898,11 +903,15 @@ in order to move to the left, we might think that we should replace ADD2 with SU
but, to leave our code as it is now: is there a value of speed-x that will make x get smaller when adding them together?
in other contexts, one might say, "-1"! but we haven't used negative signs here in uxn; we can't.
in other contexts, one might say, "-1"!
but we haven't used negative signs here in uxn; we can't!
then, is there a positive value of speed-x that will make x get smaller when adding them together?
normally we could think there isn't, but here we are constrained by 8 or 16 bits. and what does that imply?
normally we would think there isn't and that the question doesn't make sense!
however, here we are constrained by 8 or 16 bits. and what does that imply?
for example, if we have the number ffff (16 bits, all are ones), and we add 0001, what do we get?
@ -913,11 +922,11 @@ for example, if we have the number ffff (16 bits, all are ones), and we add 0001
1 0000 0000 0000 0000
```
it makes sense, but the 1 at the left sits outside the 16 bits; in other contexts it would be called the carry bit.
ok, it's a bigger number, but the 1 at the left sits outside the 16 bits! in other contexts this would be called the carry bit.
in uxn, the result of adding ffff and 0001 is 0000: we would say we are overflowing the 16 bits.
in uxn, the result of adding ffff and 0001 is 0000: we say we are overflowing the 16 bits.
let's look at it the other way around: if we have 1, and we add ffff, we get 0, that is 1 less than 1.
let's look at it the other way around: if we have 0001, and we add ffff, we get 0000, that is 1 less than 1!
if we have 0002, and we add ffff:
@ -928,11 +937,11 @@ if we have 0002, and we add ffff:
1 0000 0000 0000 0001
```
we get 0001, that is 1 less than 2.
we get 0001, that is 1 less than 2!
in general, if we add ffff to a 16 bits number, we'll get a value that is 1 less than itself.
we can think then that ffff is like a "-1"!
therefore we can think that ffff is like a "-1"!
to get other "negative numbers", let's observe the following: if we subtract 1 from ffff, we get fffe. what happens if we add it to 2?
@ -972,7 +981,7 @@ it might make sense to set these values as macros:
%BALL-NEGATIVE-SPEED { #ffff } ( -1 )
```
### implemeting the ball movement
### implementing the ball movement
based on what we just discussed, we can start our update-ball subroutine with the following:
@ -990,7 +999,7 @@ based on what we just discussed, we can start our update-ball subroutine with th
RTN
```
if we complement our initilization with the speeds, we'll be able to see the ball moving:
if we complement our setup routine with the initial speeds, we'll be able to see the ball moving:
```
( inside setup )
@ -1005,6 +1014,8 @@ BALL-POSITIVE-SPEED .ball/speed-x STZ2
BALL-POSITIVE-SPEED .ball/speed-y STZ2
```
woohoo! it moves, but for the moment it flies away :)
## collisions with the walls
we have defined the general way of updating the position of the ball given its speed in x and y.
@ -1066,7 +1077,8 @@ the y coordinate of the bottom wall would be the height of the screen, less the
(inside update ball )
&check-bottom-wall
.ball/y LDZ2 BALL-SIZE ADD2 ( y + ball size )
.Screen/height DEI2 WALL-MARGIN SUB2 ( height - margin )
.Screen/height DEI2
WALL-MARGIN SUB2 ( height - margin )
GTH2 ( is the ball y greater than the wall y? )
,&set-negative-speed JCN
,&continue JMP
@ -1083,14 +1095,16 @@ our update-ball subroutine looks like the following right now:
```
@update-ball ( -- )
( update x )
( get speed-x and x )
.ball/speed-x LDZ2 .ball/x LDZ2 ( get x )
.ball/speed-x LDZ2 .ball/x LDZ2
ADD2 ( add them together )
.ball/x STZ2 ( store new x )
( update y )
( get speed-y and y )
.ball/speed-y LDZ2 .ball/y LDZ2 ( get y )
ADD2 ( add them together )
.ball/speed-y LDZ2 .ball/y LDZ2
ADD2 ( add them together )
.ball/y STZ2 ( store new y )
( check collisions with walls )
@ -1107,8 +1121,9 @@ our update-ball subroutine looks like the following right now:
&check-bottom-wall
.ball/y LDZ2 BALL-SIZE ADD2 ( y + ball size )
.Screen/height DEI2 WALL-MARGIN SUB2 ( height - margin )
GTH2
.Screen/height DEI2
WALL-MARGIN SUB2 ( height - margin )
GTH2 ( is the ball y greater than the wall y? )
,&set-negative-speed JCN
,&continue JMP
@ -1194,7 +1209,8 @@ the whole x-in-left code would end up looking like:
,&finish JCN
&reset-left
( here you can add a point to the right paddle )
( here you can increase the score of
the right paddle )
;reset JSR2
,&finish JMP
@ -1241,7 +1257,8 @@ for the right paddle we will do the same as above, but changing the comparisons
,&finish JCN
&reset-right
( here you can add a point to the left paddle )
( here you can increase the score
of the left paddle )
;reset JSR2
,&finish JMP
@ -1667,7 +1684,7 @@ RTN
&tile3 [ ff ff fe fe fc f8 f0 c0 06 06 0c 1c 38 f0 c0 00 ]
```
whew!
whew! :)
# more possibilities