Retrospect Posted March 13, 2023 Share Posted March 13, 2023 Hello everyone. During my coding break, I decided to learn Forth. That's right. So I am starting a little project called "Schooner" ... nothing ambitious ... it's really just going to be a program that displays a little Tombstone City Schooner character on a yellow screen and lets the player move it around, and eventually fire a missile. Anything else more than that will depend upon whether my head has fried or not. So I started using Camel99 Forth and that's what my project runs on. So far, I've managed to make the screen do this .... it wasn't intentional though. Don'cha think it looks nice! 8 Quote Link to comment Share on other sites More sharing options...
Retrospect Posted March 13, 2023 Author Share Posted March 13, 2023 Schooner (Camel99).txt < Documented Source. Includes line that made the crash happen labelled as "this does not work - help" 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 13, 2023 Share Posted March 13, 2023 DECIMAL : B 0 23 DO 0 I 131 1 HCHAR LOOP ; \ *** THIS DOES NOT WORK - HELP!!!! Remember DO needs the numbers reversed. 23 0 DO 1 Quote Link to comment Share on other sites More sharing options...
Retrospect Posted March 13, 2023 Author Share Posted March 13, 2023 5 minutes ago, TheBF said: Remember DO needs the numbers reversed. 23 0 DO Thankyou . So : B 23 0 DO 0 I 131 1 HCHAR LOOP ; should be okay? I can feel my brain sizzling lol But it's still fun to do so long as I don't try to get above myself and start thinking "Why the heck can't I do Avaris yet" 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 13, 2023 Share Posted March 13, 2023 1 minute ago, Retrospect said: Thankyou . So : B 23 0 DO 0 I 131 1 HCHAR LOOP ; should be okay? I can feel my brain sizzling lol But it's still fun to do so long as I don't try to get above myself and start thinking "Why the heck can't I do Avaris yet" Exactly. Slow and steady. 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 13, 2023 Share Posted March 13, 2023 Oh and you forgot the " after all those strings. 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 13, 2023 Share Posted March 13, 2023 The characters after 127 don't have any colors assigned to them. Maybe I should change that when GRAFIX loads up. But in the mean time you need to assign a color to any character from 128 to 255 131 SET# 2 1 COLOR will get you started. 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 13, 2023 Share Posted March 13, 2023 (edited) Here is something that you might never do in BASIC. We make a partial call with the char and the length into a new word. Then we pass the row,col to the new words and boom. You get walls. \ PRINT BORDERS ON SCREEN DECIMAL : HWALL ( row col --) 131 32 HCHAR ; : VWALL ( row col --) 131 24 VCHAR ; : BORDER 0 0 HWALL 0 0 VWALL 0 23 HWALL 31 0 VWALL ; This will jump start you. I know I know. It sucks without the safety net. So write a word. Then try that word in the console, passing it parameters, until it's correct. Then do that to the next word. The console is your friend. Don't try to make a pile of code and compile it all in one go. Spoiler \ 01 FIRE, 02 LEFT, 04 RIGHT, 08 DOWN, 10 UP \ CODE JOYST( JOYSTICK# -- VALUE ) INCLUDE DSK1.GRAFIX \ DEFINITIONS \ \ 96 SCHOONER UP \ 97 SCHOONER DOWN \ 98 SCHOONER LEFT \ 99 SCHOONER RIGHT \ 100 SCHOONER MISSILE \ \ 112-123 LARGE TITLE \ 128-132 RED BORDER & MOUNTAINS DECIMAL : DEFINE-SHAPES S" 001818183C7E7E42" 96 CALLCHAR S" 427E7E3C18181800" 97 CALLCHAR S" 00070E7E7E0E0700" 98 CALLCHAR S" 00E0707E7E70E000" 99 CALLCHAR S" 00003C3C3C3C0000" 100 CALLCHAR S" FCFCC0C0C0C0FCFC" 112 CALLCHAR S" 0C0C0C0C0C0CFCFC" 113 CALLCHAR S" FCFCC0C0C0C0C0C0" 114 CALLCHAR S" C0C0C0C0C0C0FCFC" 115 CALLCHAR S" CCCCCCCCCCCCFCFC" 116 CALLCHAR S" CCCCCCCCCCCCCCCC" 117 CALLCHAR S" FCFCCCCCCCCCCCCC" 118 CALLCHAR S" CCCCCCCCCCCCFCFC" 119 CALLCHAR S" CCCCCCECFCFCDCCC" 120 CALLCHAR S" FCFCC0C0C0C0F0F0" 121 CALLCHAR S" F8FCCCCCCCCCFCF8" 122 CALLCHAR S" F0F8DCCCCCCCCCCC" 123 CALLCHAR S" 80C0E0F0F8FCFEFF" 128 CALLCHAR S" C0F0FCFFFFFFFFFF" 129 CALLCHAR S" 00000000C0F0FCFF" 130 CALLCHAR S" FFFFFFFFFFFFFFFF" 131 CALLCHAR S" 00000000030F3FFF" 132 CALLCHAR S" 030F3FFFFFFFFFFF" 133 CALLCHAR S" 0103070F1F3F7FFF" 134 CALLCHAR ; \ GET DEFS, SCREEN COLOR 4 GREEN AND CLEAR IT : CLS PAGE 12 SCREEN ; : HIGH-COLORS 128 SET# 2 1 COLOR 136 SET# 2 1 COLOR ; \ PRINT BORDERS ON SCREEN DECIMAL : HWALL ( row col --) 131 32 HCHAR ; : VWALL ( row col --) 131 24 VCHAR ; : BORDER 0 0 HWALL 0 0 VWALL 0 23 HWALL 31 0 VWALL ; \ WAIT FOR A KEYPRESS : MYKEY BEGIN KEY? ?DUP UNTIL ; : RUN CLS DEFINE-SHAPES HIGH-COLORS BORDER MYKEY ; Edited March 13, 2023 by TheBF typo 1 1 Quote Link to comment Share on other sites More sharing options...
Retrospect Posted March 13, 2023 Author Share Posted March 13, 2023 Thank you @TheBF you are a star. I have borders now. I colored them red for my game. Next on my To-Do list is displaying a large title "schooner" ... I'll proudly show the screenshot of that when I get it working I see a better style of programming Forth from your reworking of my code. It's good that the words can be arranged like that, in my mind I was thinking this: (dunno why!) : RUN word word word word word ; But your example shows : RUN word word word word ; And that is so much better and sits better in my mind at least! Quote Link to comment Share on other sites More sharing options...
Retrospect Posted March 13, 2023 Author Share Posted March 13, 2023 31 minutes ago, TheBF said: Oh and you forgot the " after all those strings. .... and it is a mystery to me why I took them out, I must have done at some point. Hell I don't even know why?! 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 13, 2023 Share Posted March 13, 2023 Vertical or horzizontal has been a discussion with Forth. The compiler doesn't care so do what makes sense to you. Once you have your own set of words for the GAME a sentence format might look super. But for hard stuff I go vertical and put comments beside each line sometimes to keep my head aligned. It is more like Assembler that way. Quote Link to comment Share on other sites More sharing options...
Retrospect Posted March 13, 2023 Author Share Posted March 13, 2023 2 minutes ago, TheBF said: But for hard stuff I go vertical and put comments beside each line sometimes to keep my head aligned. It is more like Assembler that way. That would be the perfect way for me. 'Specially with the comments. Quote Link to comment Share on other sites More sharing options...
Retrospect Posted March 14, 2023 Author Share Posted March 14, 2023 Success !! Large letter title now displayed atop the screen just inside the red borders. 3 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 14, 2023 Share Posted March 14, 2023 (edited) Since we are doing a bit of teaching in this thread here is a thought for all those patterns. Naming the strings is fair ball in BASIC or Forth but it's not as obvious in Forth. (Ok I know. Nothing is in Forth) In BASIC you might do: BLOCK$="FFFFFFFFFFFFFFFF" Then use it later for different characters. CALL CHAR( 121,BLOCK$) In Forth the S" word parses a string up to a final ". If we are interpreting, S" leaves the address of the string and the length on the data stack. If we are compiling in a colon definition, S" compiles the string into the colon definition and when you run that new word it return the address and length. Like this : BLOCK$ S" FFFFFFFFFFFFFFFF" ; Now in a similar manner we could say this in our program. BLOCK$ 121 CALLCHAR dirty little secret CALLCHAR is part of the words I call "training wheels" that I added so people could move from TI BASIC to Forth in more comfort. The truth is that keeping the data as a string uses 2x more space than if we stored the actually integers that need to go into VDP RAM. There are a couple of ways to do this differently that we can demonstrate once @Retrospect 's program is running. Edited March 14, 2023 by TheBF fixed typos 2 2 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 14, 2023 Share Posted March 14, 2023 The question came up about making a star field for this schooner project. @retrospect PMed me with his BASIC code that uses a number of arrays. A short list of 8 star characters, each one bit shifted 2 arrays of coordinates for the x,y locations of the the starts. 1 array of the character that is on the screen, so we can bump it to the next bit shifted star. The code steps through the screen locations and bumps each star character but the code must wrap around the list of 8 characters and wrap back to the start of the other 3 arrays. This is all "kosher" BASIC. Works fine. I explored making some words to duplicate all that but realized it seemed way more work than needed. In Forth (or C, or Assembler) we can touch memory directly. We can even touch the VDP chip memory directly. So its faster to go direct to the VDP memory to update the screen. VPEEK() in Camel99 is VC@ "video character fetch" VPOKE() is VC! "video character store" Here is what I came up with. It uses one weird concept that may take some explanation. In Forth we can use the interpreter to run some code while we are compiling. So in this case we made a word that compiles random screen addresses into memory. That becomes an array of locations that was generated when the file compiles. Spoiler INCLUDE DSK1.TOOLS INCLUDE DSK1.GRAFIX INCLUDE DSK1.RANDOM \ define our stars DECIMAL S" 0000000100000000" 40 CALLCHAR S" 0000000200000000" 41 CALLCHAR S" 0000000400000000" 42 CALLCHAR S" 0000000800000000" 43 CALLCHAR S" 0000001000000000" 44 CALLCHAR S" 0000002000000000" 45 CALLCHAR S" 0000004000000000" 46 CALLCHAR S" 0000000000000000" 47 CALLCHAR : NEXT-STAR ( char -- char') 1+ 48 OVER = IF DROP 40 THEN ; \ : TESTNEXT 40 BEGIN NEXT-STAR DUP . ?TERMINAL UNTIL ; : RND-STAR ( -- char) 8 RND 40 + ; \ : RNDX ( -- x) 32 RND ; \ : RNDY ( -- y) 24 RND ; : RND-VADDR ( -- Vaddr) C/SCR @ RND \ get random address from zero to size of screen VPG @ + ; \ get the video page, add to the random number 32 CONSTANT #STARS \ lock this down as a constant \ "compile" random video addresses into memory with comma \ comma in the name LOCATIONS, reminds us what this word does. : LOCATIONS, ( n --) 0 DO RND-VADDR , LOOP ; \ ******************************************************* \ This is a strange thing. We can use the interpreter to \ make a table of data when the file is "INCLUDED" \ ****************************************************** \ Now we can make oa table of data at compile time CREATE STAR-LOCATIONS #STARS LOCATIONS, \ make a way to access the table by number. (makes an array) :-) \ and use @ to fetch the value in cell 'n' : ]LOCATION ( n -- Vaddr) CELLS STAR-LOCATIONS + @ ; \ Put the stars on the screen at the random STAR-LOCATIONS : .STARS #STARS 0 DO RND-STAR I ]LOCATION VC! \ write star to video memory LOOP ; : SHIFT-STARS #STARS 0 DO I ]LOCATION DUP \ need to copies VC@ \ read star character from screen location NEXT-STAR \ bump it to next star character SWAP VC! \ write back new character to screen LOOP ; : TEST PAGE 40 SET# 16 1 COLOR 2 SCREEN .STARS BEGIN SHIFT-STARS ?TERMINAL UNTIL 8 SCREEN ; There are optimizations that could be made like using binary wrap for the NEXT-CHAR word. I am not sure the look is correct yet. The video is running with no delays anywhere. starfield1.mp4 2 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted March 14, 2023 Share Posted March 14, 2023 1 hour ago, TheBF said: There are optimizations that could be made like using binary wrap for the NEXT-CHAR word. Here is one: : NEXT-STAR ( char -- char') 1+ \ increment character 7 AND \ force right nybble to range 0..7 40 + \ add back stripped-off 40 ; 1 Quote Link to comment Share on other sites More sharing options...
Retrospect Posted March 14, 2023 Author Share Posted March 14, 2023 2 hours ago, TheBF said: The question came up about making a star field for this schooner project. @retrospect PMed me with his BASIC code that uses a number of arrays. A short list of 8 star characters, each one bit shifted 2 arrays of coordinates for the x,y locations of the the starts. 1 array of the character that is on the screen, so we can bump it to the next bit shifted star. The code steps through the screen locations and bumps each star character but the code must wrap around the list of 8 characters and wrap back to the start of the other 3 arrays. This is all "kosher" BASIC. Works fine. I explored making some words to duplicate all that but realized it seemed way more work than needed. In Forth (or C, or Assembler) we can touch memory directly. We can even touch the VDP chip memory directly. So its faster to go direct to the VDP memory to update the screen. VPEEK() in Camel99 is VC@ "video character fetch" VPOKE() is VC! "video character store" Here is what I came up with. It uses one weird concept that may take some explanation. In Forth we can use the interpreter to run some code while we are compiling. So in this case we made a word that compiles random screen addresses into memory. That becomes an array of locations that was generated when the file compiles. Reveal hidden contents INCLUDE DSK1.TOOLS INCLUDE DSK1.GRAFIX INCLUDE DSK1.RANDOM \ define our stars DECIMAL S" 0000000100000000" 40 CALLCHAR S" 0000000200000000" 41 CALLCHAR S" 0000000400000000" 42 CALLCHAR S" 0000000800000000" 43 CALLCHAR S" 0000001000000000" 44 CALLCHAR S" 0000002000000000" 45 CALLCHAR S" 0000004000000000" 46 CALLCHAR S" 0000000000000000" 47 CALLCHAR : NEXT-STAR ( char -- char') 1+ 48 OVER = IF DROP 40 THEN ; \ : TESTNEXT 40 BEGIN NEXT-STAR DUP . ?TERMINAL UNTIL ; : RND-STAR ( -- char) 8 RND 40 + ; \ : RNDX ( -- x) 32 RND ; \ : RNDY ( -- y) 24 RND ; : RND-VADDR ( -- Vaddr) C/SCR @ RND \ get random address from zero to size of screen VPG @ + ; \ get the video page, add to the random number 32 CONSTANT #STARS \ lock this down as a constant \ "compile" random video addresses into memory with comma \ comma in the name LOCATIONS, reminds us what this word does. : LOCATIONS, ( n --) 0 DO RND-VADDR , LOOP ; \ ******************************************************* \ This is a strange thing. We can use the interpreter to \ make a table of data when the file is "INCLUDED" \ ****************************************************** \ Now we can make oa table of data at compile time CREATE STAR-LOCATIONS #STARS LOCATIONS, \ make a way to access the table by number. (makes an array) :-) \ and use @ to fetch the value in cell 'n' : ]LOCATION ( n -- Vaddr) CELLS STAR-LOCATIONS + @ ; \ Put the stars on the screen at the random STAR-LOCATIONS : .STARS #STARS 0 DO RND-STAR I ]LOCATION VC! \ write star to video memory LOOP ; : SHIFT-STARS #STARS 0 DO I ]LOCATION DUP \ need to copies VC@ \ read star character from screen location NEXT-STAR \ bump it to next star character SWAP VC! \ write back new character to screen LOOP ; : TEST PAGE 40 SET# 16 1 COLOR 2 SCREEN .STARS BEGIN SHIFT-STARS ?TERMINAL UNTIL 8 SCREEN ; There are optimizations that could be made like using binary wrap for the NEXT-CHAR word. I am not sure the look is correct yet. The video is running with no delays anywhere. starfield1.mp4 4.45 MB · 0 downloads So the stars patterns are moving from 40 to 47. If it's possible to do, when any individual star reaches pattern 47, and it goes back to 40, then that star should be deleted and displayed again 1 char to the left. If left <1 then display it at char position 32. That way, you get them moving across the screen. I'm all good saying this, but I can only do this in XB (or ti basic) ... I wouldn't know how to visit each star and do that. Quote Link to comment Share on other sites More sharing options...
Retrospect Posted March 14, 2023 Author Share Posted March 14, 2023 Also to note, I may have mislead somewhat ... the starfield thing, is not for the Schooner game. The Schooner game will be my first attempt at a game in Forth ... once I've mastered that, and maybe some more little games ... the starfield is for another Forth game. That game will be called "Avaris - Anubis Arises" and it will be exclusive to Forth. That's my ultimate target. Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 14, 2023 Share Posted March 14, 2023 1 hour ago, Lee Stewart said: Here is one: : NEXT-STAR ( char -- char') 1+ \ increment character 7 AND \ force right nybble to range 0..7 40 + \ add back stripped-off 40 ; LOL. Ya I tried that and it didn't work quite right so I will have work on why. Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 14, 2023 Share Posted March 14, 2023 1 hour ago, Retrospect said: So the stars patterns are moving from 40 to 47. If it's possible to do, when any individual star reaches pattern 47, and it goes back to 40, then that star should be deleted and displayed again 1 char to the left. If left <1 then display it at char position 32. That way, you get them moving across the screen. I'm all good saying this, but I can only do this in XB (or ti basic) ... I wouldn't know how to visit each star and do that. Ah ok I get it now. "if it's possible to do..." BFs two rules of software: 1. Anything is possible. 2. Nothing is easy. They have never let me down. That may take a bit more head scratching for a "Forth way to do it". At some point Joe, I might have to have private tutor session to explain what I did there. As you can see it looks very different than BASIC, because I choose not to do it the way you must do it in BASIC. 2 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 15, 2023 Share Posted March 15, 2023 (edited) Ok this game stuff is way harder than I thought. (subtext I suck as a programmer) But here is what I finally came up with. I changed the original code to use a library array, mostly because it is more understandable. NEW-STARS fills that array up with random VDP addresses that fit on the screen. I run NEW-STARS at compile time to initialize the array. The biggest difference between this and the BASIC code (see post on the RXB thread by @Retrospect) is in BASIC you tend to think in x,y coordinates for the screen. When you get close to the hardware you can think of addresses in VDP RAM. So we are handling less numbers here because each star is in a single VDP address. We we do the bit migration to the left with different chars and when we get to the last character, we just erase the old character subtract 1 from the VDP address, protecting the address from going negative test if the address is on the left edge of the screen if it is add 31 to the address (go back to the right side) Store the new VDP address in the LOCATION array. I think it's pretty close to what is going on in BASIC now. Spoiler INCLUDE DSK1.TOOLS INCLUDE DSK1.GRAFIX INCLUDE DSK1.RANDOM INCLUDE DSK1.ARRAYS \ define our stars DECIMAL S" 0000000100000000" 40 CALLCHAR S" 0000000200000000" 41 CALLCHAR S" 0000000400000000" 42 CALLCHAR S" 0000000800000000" 43 CALLCHAR S" 0000001000000000" 44 CALLCHAR S" 0000002000000000" 45 CALLCHAR S" 0000004000000000" 46 CALLCHAR S" 0000000000000000" 47 CALLCHAR : NEXT-STAR ( char -- char') 1+ 7 AND 40 + ; \ : TESTNEXT 40 BEGIN NEXT-STAR SWAP . UNTIL ; : RND-STAR ( -- char) 8 RND 40 + ; : RND-VADDR ( -- Vaddr) C/SCR @ RND \ get random address from zero to size of screen VPG @ + ; \ get the video page, add to the random number 32 CONSTANT #STARS \ lock this down as a constant \ array that holds the VDP address of every star #STARS ARRAY ]LOCATION : NEW-STARS ( n --) #STARS 0 DO RND-VADDR I ]LOCATION ! LOOP ; NEW-STARS \ initialize the array now \ This array FETCHES the star's VDP screen address from ]location : ]VDPLOC ( n -- Vaddr) ]LOCATION @ ; \ Put the stars on the screen at the random LOCATION in our LOCATIONS array : .STARS #STARS 0 DO RND-STAR I ]VDPLOC VC! \ write star to video memory LOOP ; \ Given a screen address, test if we hit the left edge of the screen : LEFT-EDGE? ( n -- ?) C/L @ MOD 0= ; \ modulo divide by "chars per line" \ Take the address of a cell in ]LOCATION array. \ get the screen location of a star \ move it 1 one left, but address can't go below zero so stop that. \ If we hit the left edge add 31 to the Vaddr and store it back in Address : MOVELEFT ( addr -- ) \ decrement a variable to 0 but not below DUP @ ( -- addr Vaddr) BL OVER VC! \ erase char in old screen location 1- 0 MAX ( -- addr Va) \ subtract 1 but don't go below 0 DUP LEFT-EDGE? \ test if we are at the edge of the screen IF 31 + \ yes. Add 31 to go back to right side of screen THEN SWAP ! ; \ store this new location in the addr of ]LOCATION array ; : SHIFT-STARS #STARS 0 DO I ]VDPLOC VC@ \ read star character from screen location NEXT-STAR \ advance to the next bit character DUP 47 = ( -- Va c ?) IF I ]LOCATION MOVELEFT THEN I ]VDPLOC VC! \ store the new star at the VDP location LOOP ; : TEST PAGE 40 SET# 16 1 COLOR 2 SCREEN .STARS BEGIN SHIFT-STARS ?TERMINAL UNTIL 8 SCREEN ; startfield2.mp4 Edited March 15, 2023 by TheBF edited .STARS 1 Quote Link to comment Share on other sites More sharing options...
Retrospect Posted March 15, 2023 Author Share Posted March 15, 2023 that's brilliant Brian! I should save that code because in 20 years time when I nail Forth I'm making Avaris 3 with that starfield, haha 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 15, 2023 Share Posted March 15, 2023 Does the idea of using Video addresses instead X,Y coordinates make sense? If not ask away. Quote Link to comment Share on other sites More sharing options...
Retrospect Posted March 15, 2023 Author Share Posted March 15, 2023 5 minutes ago, TheBF said: Does the idea of using Video addresses instead X,Y coordinates make sense? If not ask away. I am going to make a guess here that a video address being only a single number means the top left of the screen is zero and bottom right is 767. So the middle of the screen is somewhere around 320? Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 15, 2023 Share Posted March 15, 2023 2 minutes ago, Retrospect said: I am going to make a guess here that a video address being only a single number means the top left of the screen is zero and bottom right is 767. So the middle of the screen is somewhere around 320? Yes sir. And by going with addresses we are handling 1/2 the numbers and so less math. I think it worked out pretty well. You could do the same thing I did in BASIC with VPEEK() and VPOKE() and single array that holds the VDP addresses. 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.