Jump to content
IGNORED

a few quick questions about larger projects and variable names


Recommended Posts

On 9/1/2021 at 2:47 AM, carlsson said:

It probably is considered quite non-standard.

yea for sure.  i think that would be a "cross that bridge when you get to it" if you ever really find somehow you need more ram for a game.  However it really does make you wonder if developers would benefit from more actual ram like the chess game..  i would imagine homebrew developers would LOVE to have more ram.. 

 

non-standard for sure, but maybe it shouldn't be? :)

 

makes me think of the super game cartridge for colecovision..  wouldn't that be wild.  someone were to make some kind of similar hardware boosting device..  though i realize that creates an EVEN MORE niche product that requires a 3rd party piece of gear.  though i say that with every intent and dreamy (however foolish) hope to make games that uses intellivoice 

Link to comment
Share on other sites

50 minutes ago, Caleb Garner said:

yea for sure.  i think that would be a "cross that bridge when you get to it" if you ever really find somehow you need more ram for a game.  However it really does make you wonder if developers would benefit from more actual ram like the chess game..  i would imagine homebrew developers would LOVE to have more ram.. 

 

non-standard for sure, but maybe it shouldn't be? :)

 

Let us be clear that there are already 8K of additional 16-bit on-board RAM in the LTO Flash!, which are also supported by the jzIntv emulator and some (if not all) home-brew PCB boards out there (it turns out that, due to modern hardware components, it is harder to make a cartridge with only enough space for an old Mattel game, than it is to make one that gains ample space for free).

 

8K of RAM is a substantial amount -- especially for a system in which most games are accustomed to using no more than a few hundred bytes.

 

A lot of us consider those extra 8K words of RAM as standard.  In fact, I ran a poll a few years back asking about what sort of enhanced features programmers currently employ, which ones they wish they had, and which ones are completely ignored; and the collective answer suggested that a not-insignificant number of respondents considered additional RAM to be a pretty much de facto standard.

 

I am not one to tempt fate, so I won't say that 8K will be enough for every game, but I will urge you to first make a game and get acquainted with the hardware as it is before you start contemplating what theoretical limitations you may encounter in some hypothetical über-large game.

 

My guess is that, as many of us have found out, with 8K of extra RAM, memory is no longer the primary concern.  There is also CPU speed, memory map constraints, and many other pesky limitations that afflict us (only 8 MOBs! only 64 custom cards in GRAM! only 3 sound channels for music and sound effects! no more than 2 colors per card! no practical way to use the Intellivoice for sampled voices!).

 

Quote

makes me think of the super game cartridge for colecovision..  wouldn't that be wild.  someone were to make some kind of similar hardware boosting device..  though i realize that creates an EVEN MORE niche product that requires a 3rd party piece of gear.  though i say that with every intent and dreamy (however foolish) hope to make games that uses intellivoice 

Somewhere in the vast AtariAge forum landscape, there is a graveyard full of entire threads discussing that very notion.  Feel free to search for them and add your 2 cents.  ;)

 

For the record, I am not against any of those enhancements in principle.  I just think that the ultra-small community of Intellivision programmers already struggles to maximize the use of what is available today.  New gadgets and additional features may not change that in a meaningful way.

 

Anyway, back to programming ...

 

     -dZ.

Edited by DZ-Jay
  • Like 1
Link to comment
Share on other sites

Btw @Caleb Garner since you seem to like to dig out all possibilities in parallel to getting any development done, you might be interested in this discussion about what it would take to expand GRAM: https://atariage.com/forums/topic/319546-expanded-gram/

 

Spoiler: It takes quite a bit of internal modifications.

  • Like 1
Link to comment
Share on other sites

 

28 minutes ago, carlsson said:

discussion about what it would take to expand GRAM:

Wow awesome.  Yea glad it has been explored!  Just fascinating. 
 

as for the ram and such i do see how 8kb for such a system is a lot!  Sprite sip ram like nothing.  When I look at games like AF with so many unique levels and backgrounds. I have nothing to worry about. 
 

 

As for development i am finished with chapter 3. However i am trying to tinker with the example (twinkle twinkle) and figure out how to stop the random dot drawing when the music ends.  My attempts so far have not succeeded. After that it is on to the pong game. 

 

there is a way the loop is setup that seems like it is “1” is there do the loop.  As if it is just saying “as long a 1 is 1 do the thing). But 1 isn’t a variable so I thought i could define a variable in its place and when stop music command at the end fires off change the variable value and that would stop it.  I think my logic is sound but my syntax is wrong

 

 

  • Like 1
Link to comment
Share on other sites

38 minutes ago, Caleb Garner said:

Wow awesome.  Yea glad it has been explored!  Just fascinating. 
 

as for the ram and such i do see how 8kb for such a system is a lot!  Sprite sip ram like nothing.  When I look at games like AF with so many unique levels and backgrounds. I have nothing to worry about.

8K = 8,192 x 16-bit words, not bytes.

 

Quote

As for development i am finished with chapter 3. However i am trying to tinker with the example (twinkle twinkle) and figure out how to stop the random dot drawing when the music ends.  My attempts so far have not succeeded. After that it is on to the pong game. 

If you'd like to post some of your code, someone could point to the problem, or offer some suggestions.

 

Quote

there is a way the loop is setup that seems like it is “1” is there do the loop.  As if it is just saying “as long a 1 is 1 do the thing).

That is a typical "infinite loop."  You may find it in other programming languages as well, something like "while (true) ... ", etc.

 

Quote

But 1 isn’t a variable so I thought i could define a variable in its place and when stop music command at the end fires off change the variable value and that would stop it.  I think my logic is sound but my syntax is wrong

That is one way to do it:  to employ a "sentinel" variable which will then loop until some conditional expression evaluates to an expected.

 

Another way is to test the condition within the loop, and break out with an "EXIT WHILE" statement.

 

If your syntax is wrong, the compiler would complain.  If it compiled successfully, but it doesn't behave as you expect, then it's an error in the applied logic.  I recommend you post your loop code here so that we can help you troubleshoot it.

 

   -dZ.

Edited by DZ-Jay
Link to comment
Share on other sites

Note that both GRAM used for current characters and sprite definitions, and BACKTAB used for the screen matrix are part of the internal memory. The kind of data you can store on the cartridge is predefined patterns and screens which are copied from cartridge ROM to system RAM using commands like DEFINE and SCREEN.

 

I realized that the 8000 decles of JLP memory you can enable lies outside of the 42K map, so possibly you could use that for double buffering self-modifying graphics that you copy into the actual locations in system RAM, without compromising the total ROM size.

 

For comparison, a full set of 64 GRAM equals 256 decles (64 x 8 = 512 bytes / 2 = 256) and a full BACKTAB screen has 20x12 = 240 decles. It means that e.g. in segment #3 which consists of 3840 decles between $2100 and $2FFF (about 9% of the total 42K space), you could fit 15 full sets of either GRAM or screens before getting into dynamically calculating graphics data to store into cartridge RAM and then copied to system RAM. I can see a program that simulates hires graphics like a wireframe or one that heavily uses moving software sprites besides the hardware MOBs, would in particular have use of cartridge RAM if multiple sets of predefined graphics are not enough. I can't speak for AF or other Kai Magazine and other developers' productions if they employ such methods.

Link to comment
Share on other sites

1 minute ago, carlsson said:

Note that both GRAM used for current characters and sprite definitions, and BACKTAB used for the screen matrix are part of the internal memory. The kind of data you can store on the cartridge is predefined patterns and screens which are copied from cartridge ROM to system RAM using commands like DEFINE and SCREEN.

 

I realized that the 8000 decles of JLP memory you can enable lies outside of the 42K map, so possibly you could use that for double buffering self-modifying graphics that you copy into the actual locations in system RAM, without compromising the total ROM size.

Still ... how do they get there?  If that memory range is defined as Read/Write memory, then it will be empty when the cartridge boots up.  You would probably have to encode and compress the data somewhere, then decode it into RAM in order for them to become useful for the program.

 

Moreover, the code that implements the logic to decode must also be stored in ROM.

 

That is a practical technique, indeed, but doesn't come for free:  you've just traded time for space.

 

To be sure, for GRAM cycling, the constraint is not so much the available space, but the time afforded by the VBLANK 2 period.

 

I do not know how it is done in other games, but I can say that on my own Christmas Carol, all picture data for GRAM is stored in ROM in various sets, according to their function.  For instance, all the pictures comprising a sprite's animation sequence are stored contiguously, and each is loaded as necessary, iterating through the sequence by advancing a "cursor" pointing to the next key frame.

 

Here's an example of the Snowman's walking animation:

Spoiler

; ===================================================================
; The tiles are stored in a compacted format, where the odd lines
; form the low-order bytes, and the even lines the high-order bytes.
; For example, the following two lines,
;           ########        ; odd line
;           ........        ; even line
;
; will be stored as follows,
;           DECLE $00FF     ; not $FF00 !
;
; This shaves a chunk of cycles when block-copying each tile into
; GRAM, which is always a Good Thing.
;
; Copyright (c) 2010-2021, James Pujals (DZ-Jay)
; ===================================================================

SNOWMAN_DATA    PROC
@@data_start:
@@Horiz:
                ; Animation Tile: 0  (ID: 0)
                ; --------------------------------
                            ; ..####.. - %00111100
                DECLE $7E3C ; .######. - %01111110
                            ; .#.#.##. - %01010110
                DECLE $7E56 ; .######. - %01111110
                            ; .##..##. - %01100110
                DECLE $3466 ; ..##.#.. - %00110100
                            ; .######. - %01111110
                DECLE $6E7E ; .##.###. - %01101110
                            ; ######## - %11111111
                DECLE $EFFF ; ###.#### - %11101111
                            ; ######## - %11111111
                DECLE $EFFF ; ###.#### - %11101111
                            ; ######## - %11111111
                DECLE $7EFF ; .######. - %01111110
                            ; .######. - %01111110
                DECLE $3C7E ; ..####.. - %00111100
                ; --------------------------------

                ; Animation Tile: 1  (ID: 1)
                ; --------------------------------
                            ; .####... - %01111000
                DECLE $FC78 ; ######.. - %11111100
                            ; #.#.##.. - %10101100
                DECLE $FCAC ; ######.. - %11111100
                            ; ##..##.. - %11001100
                DECLE $68CC ; .##.#... - %01101000
                            ; .#####.. - %01111100
                DECLE $5E7C ; .#.####. - %01011110
                            ; ######## - %11111111
                DECLE $DFFF ; ##.##### - %11011111
                            ; ######## - %11111111
                DECLE $EFFF ; ###.#### - %11101111
                            ; ######## - %11111111
                DECLE $7EFF ; .######. - %01111110
                            ; .######. - %01111110
                DECLE $3C7E ; ..####.. - %00111100
                ; --------------------------------

                ; Animation Tile: 2  (ID: 2)
                ; --------------------------------
                            ; ........ - %00000000
                DECLE $7800 ; .####... - %01111000
                            ; ######.. - %11111100
                DECLE $ACFC ; #.#.##.. - %10101100
                            ; ######.. - %11111100
                DECLE $CCFC ; ##..##.. - %11001100
                            ; .####... - %01111000
                DECLE $7E78 ; .######. - %01111110
                            ; ##.##### - %11011111
                DECLE $FFDF ; ######## - %11111111
                            ; ##.##### - %11011111
                DECLE $FFDF ; ######## - %11111111
                            ; ###.#### - %11101111
                DECLE $FFEF ; ######## - %11111111
                            ; .######. - %01111110
                DECLE $1E7E ; ...####. - %00011110
                ; --------------------------------

                ; Animation Tile: 3  (ID: 2)
                ; --------------------------------
                            ; ........ - %00000000
                DECLE $7800 ; .####... - %01111000
                            ; ######.. - %11111100
                DECLE $ACFC ; #.#.##.. - %10101100
                            ; ######.. - %11111100
                DECLE $CCFC ; ##..##.. - %11001100
                            ; .####... - %01111000
                DECLE $7E78 ; .######. - %01111110
                            ; ##.##### - %11011111
                DECLE $FFDF ; ######## - %11111111
                            ; ##.##### - %11011111
                DECLE $FFDF ; ######## - %11111111
                            ; ###.#### - %11101111
                DECLE $FFEF ; ######## - %11111111
                            ; .######. - %01111110
                DECLE $1E7E ; ...####. - %00011110
                ; --------------------------------

                ; Animation Tile: 4  (ID: 1)
                ; --------------------------------
                            ; .####... - %01111000
                DECLE $FC78 ; ######.. - %11111100
                            ; #.#.##.. - %10101100
                DECLE $FCAC ; ######.. - %11111100
                            ; ##..##.. - %11001100
                DECLE $68CC ; .##.#... - %01101000
                            ; .#####.. - %01111100
                DECLE $5E7C ; .#.####. - %01011110
                            ; ######## - %11111111
                DECLE $DFFF ; ##.##### - %11011111
                            ; ######## - %11111111
                DECLE $EFFF ; ###.#### - %11101111
                            ; ######## - %11111111
                DECLE $7EFF ; .######. - %01111110
                            ; .######. - %01111110
                DECLE $3C7E ; ..####.. - %00111100
                ; --------------------------------

                ; Animation Tile: 5  (ID: 0)
                ; --------------------------------
                            ; ..####.. - %00111100
                DECLE $7E3C ; .######. - %01111110
                            ; .#.#.##. - %01010110
                DECLE $7E56 ; .######. - %01111110
                            ; .##..##. - %01100110
                DECLE $3466 ; ..##.#.. - %00110100
                            ; .######. - %01111110
                DECLE $6E7E ; .##.###. - %01101110
                            ; ######## - %11111111
                DECLE $EFFF ; ###.#### - %11101111
                            ; ######## - %11111111
                DECLE $EFFF ; ###.#### - %11101111
                            ; ######## - %11111111
                DECLE $7EFF ; .######. - %01111110
                            ; .######. - %01111110
                DECLE $3C7E ; ..####.. - %00111100
                ; --------------------------------

                ; Animation Tile: 6  (ID: 3)
                ; --------------------------------
                            ; ...####. - %00011110
                DECLE $3F1E ; ..###### - %00111111
                            ; ..#.#.## - %00101011
                DECLE $3F2B ; ..###### - %00111111
                            ; ..##..## - %00110011
                DECLE $1A33 ; ...##.#. - %00011010
                            ; ..#####. - %00111110
                DECLE $763E ; .###.##. - %01110110
                            ; ######## - %11111111
                DECLE $F7FF ; ####.### - %11110111
                            ; ######## - %11111111
                DECLE $EFFF ; ###.#### - %11101111
                            ; ######## - %11111111
                DECLE $7EFF ; .######. - %01111110
                            ; .######. - %01111110
                DECLE $3C7E ; ..####.. - %00111100
                ; --------------------------------

                ; Animation Tile: 7  (ID: 4)
                ; --------------------------------
                            ; ........ - %00000000
                DECLE $1E00 ; ...####. - %00011110
                            ; ..###### - %00111111
                DECLE $2B3F ; ..#.#.## - %00101011
                            ; ..###### - %00111111
                DECLE $333F ; ..##..## - %00110011
                            ; ...####. - %00011110
                DECLE $7E1E ; .######. - %01111110
                            ; #####.## - %11111011
                DECLE $FFFB ; ######## - %11111111
                            ; ####.### - %11110111
                DECLE $FFF7 ; ######## - %11111111
                            ; ###.#### - %11101111
                DECLE $FFEF ; ######## - %11111111
                            ; .######. - %01111110
                DECLE $787E ; .####... - %01111000
                ; --------------------------------

                ; Animation Tile: 8  (ID: 4)
                ; --------------------------------
                            ; ........ - %00000000
                DECLE $1E00 ; ...####. - %00011110
                            ; ..###### - %00111111
                DECLE $2B3F ; ..#.#.## - %00101011
                            ; ..###### - %00111111
                DECLE $333F ; ..##..## - %00110011
                            ; ...####. - %00011110
                DECLE $7E1E ; .######. - %01111110
                            ; #####.## - %11111011
                DECLE $FFFB ; ######## - %11111111
                            ; ####.### - %11110111
                DECLE $FFF7 ; ######## - %11111111
                            ; ###.#### - %11101111
                DECLE $FFEF ; ######## - %11111111
                            ; .######. - %01111110
                DECLE $787E ; .####... - %01111000
                ; --------------------------------

                ; Animation Tile: 9  (ID: 3)
                ; --------------------------------
                            ; ...####. - %00011110
                DECLE $3F1E ; ..###### - %00111111
                            ; ..#.#.## - %00101011
                DECLE $3F2B ; ..###### - %00111111
                            ; ..##..## - %00110011
                DECLE $1A33 ; ...##.#. - %00011010
                            ; ..#####. - %00111110
                DECLE $763E ; .###.##. - %01110110
                            ; ######## - %11111111
                DECLE $F7FF ; ####.### - %11110111
                            ; ######## - %11111111
                DECLE $EFFF ; ###.#### - %11101111
                            ; ######## - %11111111
                DECLE $7EFF ; .######. - %01111110
                            ; .######. - %01111110
                DECLE $3C7E ; ..####.. - %00111100
                ; --------------------------------

                ; ... SNIP! ...

 

 

 

Pictures for background scenes are stored in a similar way:  as a contiguous block of GRAM, which is then referenced from BACKTAB.  In my framework, I allocate GRAM in "chunks" I called "GRAM Blocks," which are then loaded with sets of pictures employed by various aspects of the game.  For instance, there are 2-card blocks for each 8x16 sprite, as well as blocks to hold different sections of a particular background scene or maze screen.

 

Moreover, GRAM Block allocation is done per game state/phase, so there would be one set of allocations for the title screen, one for cut-scenes, and yet another for game-play, etc.  Below is an excerpt taken from the allocations for the stage introduction sequences (cut-scenes).

 

Notice how it starts by resetting the GRAM allocation pointer, then it defines 8 blocks for the sprites.  Eventually, for the cut-scenes blocks, it truncates the allocated GRAM to "Sprite6," meaning that it will overwrite the space originally allocated for "Sprite7."

 

The main block is a chunk of 26 cards reserved for "Filler," which is then sub-allocated with overlapping blocks that can be used depending on the scene's needs, such as presents lying around or a trap for the Ghost, etc.

 

Spoiler

                ; Sprite blocks
                ; --------------------------------------
                RESET_GRAM
                DEFINE_SPRITE_GRAM(Sprite0,     vDouble)
                DEFINE_SPRITE_GRAM(Sprite1,     vDouble)
                DEFINE_SPRITE_GRAM(Sprite2,     vDouble)
                DEFINE_SPRITE_GRAM(Sprite3,     vDouble)
                DEFINE_SPRITE_GRAM(Sprite4,     vDouble)
                DEFINE_SPRITE_GRAM(Sprite5,     vDouble)        ; 12
                DEFINE_SPRITE_GRAM(Sprite6,     vDouble)        ; 14
                DEFINE_SPRITE_GRAM(Sprite7,     vSingle)        ; 15
                ; --------------------------------------


                ; ...
                ; ... Other game states ...
                ; ...


                ; Intro blocks
                ; --------------------------------------
                TRUNC_GRAM(Sprite6)                             ; 12
                DEFINE_SPRITE_GRAM(Droplet,     vSingle)        ; 1
                DEFINE_BG_GRAM    (Icicle,      ICICLE )        ; 9
                DEFINE_BG_GRAM    (Track,       TRACK  )        ; 2
                DEFINE_GRAM_BLOCK (CubeWall,     4)             ; 4
                DEFINE_GRAM_BLOCK (Filler,      26)             ; 26 <- Overlaps "SnoFlk"
                DEFINE_GRAM_BLOCK (Stub,         1)             ; 1
                DEFINE_GRAM_BLOCK (StageMsg,     9)             ; 9 (64 completed)


                ;                                   StageMsg
                ;                Filler         Stub         :  ; \
                ; ...//--------------------------|-|---------|  ;  |
                ;            Title           Emo             :  ;  |
                ; ...//----------------|    |----|           .  ;  |
                ;                      Extra                 .  ;  |_ Distribution of tiles in GRAM
                ;                      |----|                   ;  |    for Introduction Sequences.
                ;                      TrapScene                ;  |
                ;                      |--------|               ;  |
                ;                     GiftScene                 ;  |
                ;                    |----------|               ; /
                OVERLAP_GRAM_BLOCK(Title,     Filler,   0, 16)  ; Take the first 16 tiles from Filler for the Title
                OVERLAP_GRAM_BLOCK(Emoticon,  Filler,  22,  4)  ; Take the last 4 tiles from Filler for the Emoticon
                OVERLAP_GRAM_BLOCK(GiftScene, Filler,  14, 10)  ; We steal two from the Title and Emoticon for the GiftScene
                OVERLAP_GRAM_BLOCK(TrapScene, Filler,  16,  8)  ; We steal two from the Emoticon for the TrapScene
                OVERLAP_GRAM_BLOCK(Extra,     Filler,  16,  4)  ;
                OVERLAP_GRAM_BLOCK(GhostTrap, Title,   15,  1)  ; The last "Title" slot is reserved for the Ghost trap
                OVERLAP_GRAM_BLOCK(Teleportr, Emoticon, 0,  1)  ; We steal one tile from the Emoticon for the Teleporter
                ; --------------------------------------

 

 

 

These blocks are referenced by macros that serve to load the scene data into the BACKTAB.  Below is an example that uses some of the blocks above:

Spoiler

; ===================================================================
; Copyright (c) 2010-2021, James Pujals (DZ-Jay)
; ===================================================================

; ===================================================================
INTRO_BTAB      PROC
@@data_start:   ; --------------------------------------------------
@@Track:        BTAB_DATA(Track,    $00,    X_CYN,  0,  mGRAM)      ;  0
                BTAB_DATA(Track,    $01,    X_CYN,  0,  mGRAM)      ;  1
                ; --------------------------------------------------
@@Icicle:       BTAB_DATA(Icicle,   $02,    X_CYN,  0,  mGRAM)      ;  0
                BTAB_DATA(Icicle,   $00,    X_CYN,  0,  mGRAM)      ;  1
                BTAB_DATA(Icicle,   $01,    X_CYN,  0,  mGRAM)      ;  2
                BTAB_DATA(Icicle,   $02,    X_CYN,  0,  mGRAM)      ;  3
                BTAB_DATA(Icicle,   $03,    X_CYN,  0,  mGRAM)      ;  4
                BTAB_DATA(Icicle,   $04,    X_CYN,  0,  mGRAM)      ;  5
                BTAB_DATA(Icicle,   $05,    X_CYN,  0,  mGRAM)      ;  6
                BTAB_DATA(Icicle,   $07,    X_CYN,  0,  mGRAM)      ;  7
                BTAB_DATA(Icicle,   $07,    X_CYN,  0,  mGRAM)      ;  8
                BTAB_DATA(Icicle,   $07,    X_CYN,  0,  mGRAM)      ;  9
                BTAB_DATA(Icicle,   $06,    X_CYN,  0,  mGRAM)      ; 10
                BTAB_DATA(Icicle,   $02,    X_CYN,  0,  mGRAM)      ; 11
                BTAB_DATA(Icicle,   $02,    X_CYN,  0,  mGRAM)      ; 12
                BTAB_DATA(Icicle,   $07,    X_CYN,  0,  mGRAM)      ; 13
                BTAB_DATA(Icicle,   $07,    X_CYN,  0,  mGRAM)      ; 14
                BTAB_DATA(Icicle,   $05,    X_CYN,  0,  mGRAM)      ; 15
                BTAB_DATA(Icicle,   $00,    X_CYN,  0,  mGRAM)      ; 16
                BTAB_DATA(Icicle,   $01,    X_CYN,  0,  mGRAM)      ; 17
                BTAB_DATA(Icicle,   $06,    X_CYN,  0,  mGRAM)      ; 18
                BTAB_DATA(Icicle,   $02,    X_CYN,  0,  mGRAM)      ; 19
                ; --------------------------------------------------
@@Bridge:       BTAB_DATA(Icicle,   $02,    X_CYN,  0,  mGRAM)      ;  0
                BTAB_DATA(Icicle,   $08,    X_CYN,  0,  mGRAM)      ;  1
                BTAB_DATA(Icicle,   $06,    X_CYN,  0,  mGRAM)      ;  2
                BTAB_DATA(Icicle,   $02,    X_CYN,  0,  mGRAM)      ;  3
                BTAB_DATA(Icicle,   $07,    X_CYN,  0,  mGRAM)      ;  4
                BTAB_DATA(Icicle,   $03,    X_CYN,  0,  mGRAM)      ;  5
                BTAB_DATA(Icicle,   $06,    X_CYN,  0,  mGRAM)      ;  6
                BTAB_DATA(Icicle,   $03,    X_CYN,  0,  mGRAM)      ;  7
                BTAB_DATA(Icicle,   $02,    X_CYN,  0,  mGRAM)      ;  8
                BTAB_DATA(Icicle,   $05,    X_CYN,  0,  mGRAM)      ;  9
                BTAB_DATA(Icicle,   $08,    X_CYN,  0,  mGRAM)      ; 10
                BTAB_DATA(Icicle,   $02,    X_CYN,  0,  mGRAM)      ; 11
                BTAB_DATA(Icicle,   $07,    X_CYN,  0,  mGRAM)      ; 12
                BTAB_DATA(Icicle,   $06,    X_CYN,  0,  mGRAM)      ; 13
                BTAB_DATA(Icicle,   $00,    X_CYN,  0,  mGRAM)      ; 14
                BTAB_DATA(Icicle,   $08,    X_CYN,  0,  mGRAM)      ; 15
                BTAB_DATA(Icicle,   $05,    X_CYN,  0,  mGRAM)      ; 16
                BTAB_DATA(Icicle,   $02,    X_CYN,  0,  mGRAM)      ; 17
                BTAB_DATA(Icicle,   $07,    X_CYN,  0,  mGRAM)      ; 18
                BTAB_DATA(Icicle,   $00,    X_CYN,  0,  mGRAM)      ; 19

                ;       Formatted word                                 Address
                ;       ---------------------                          ----------
@@Wall:         DECLE   BTAB_GRAM_WORD(CubeWall,  $02,    X_CYN,  0), BTAB_ADDRESS( 0, 4)   ; Row #1
                DECLE   BTAB_GRAM_WORD(CubeWall,  $03,    X_CYN,  0), BTAB_ADDRESS(18, 4)   ;
                DECLE   BTAB_GRAM_WORD(CubeWall,  $00,    X_CYN,  0), BTAB_ADDRESS( 0, 5)   ; Row #2
                DECLE   BTAB_GRAM_WORD(CubeWall,  $01,    X_CYN,  0), BTAB_ADDRESS( 1, 5)   ;
                DECLE   BTAB_GRAM_WORD(CubeWall,  $00,    X_CYN,  0), BTAB_ADDRESS(18, 5)   ;
                DECLE   BTAB_GRAM_WORD(CubeWall,  $02,    X_CYN,  0), BTAB_ADDRESS(19, 5)   ;
                DECLE   BTAB_GRAM_WORD(CubeWall,  $03,    X_CYN,  0), BTAB_ADDRESS( 0, 6)   ; Row #3
                DECLE   BTAB_GRAM_WORD(CubeWall,  $00,    X_CYN,  0), BTAB_ADDRESS( 1, 6)   ;
                DECLE   BTAB_GRAM_WORD(CubeWall,  $01,    X_CYN,  0), BTAB_ADDRESS( 2, 6)   ;
                DECLE   BTAB_GRAM_WORD(CubeWall,  $01,    X_CYN,  0), BTAB_ADDRESS(17, 6)   ;
                DECLE   BTAB_GRAM_WORD(CubeWall,  $02,    X_CYN,  0), BTAB_ADDRESS(18, 6)   ;
                DECLE   BTAB_GRAM_WORD(CubeWall,  $03,    X_CYN,  0), BTAB_ADDRESS(19, 6)   ;

@@wall_count    EQU     (($ - @@Wall) / 2)

@@data_end:     ; --------------------------------------------------
                ENDP
; ===================================================================

 

 

"Track," "CubeWall," and "Icicle," are all GRAM Blocks allocated and loaded beforehand; and then referred by the BACKTAB data representing various regions of the scene.

 

For arbitrary text, the custom character sets are allocated and loaded in a similar way.  Here's the GRAM Block allocation directives for the custom fonts:

Spoiler

                ; Text-Screen blocks
                ; --------------------------------------
                RESET_GRAM
                DEFINE_GRAM_BLOCK(FontUpper,    26)             ; \
                DEFINE_GRAM_BLOCK(FontLower,    25)             ;  > 64
                DEFINE_GRAM_BLOCK(FontSymbol,   13)             ; /

 

 

 

However, most scenes employ only limited text, so smaller blocks are reserved for the specific characters required; or the characters used for a particular phrase are loaded dynamically into a generic "message" block.  That leaves most of GRAM available for graphical detail:

Spoiler

                ; Global blocks
                ; --------------------------------------
                TRUNC_GRAM(Sprite0 + .MsgBlock)                 ; 64 - 10 = 54
                DEFINE_GRAM_BLOCK (Message, 10)                 ; 10 (64 completed)
                ; --------------------------------------

 

 

 

Ultimately, there are dozens such data files in the Christmas Carol source, most of them for sprite animations.

 

           -dZ.

  • Thanks 1
Link to comment
Share on other sites

5 hours ago, DZ-Jay said:

8K = 8,192 x 16-bit words, not bytes.

so that's actually more than a 8kb?  it seems like a 16bit word is more data than a byte?  or is it smaller?  a byte as i understand it is 8 bits of data..  meaning 8 sets of 0's and 1's..  like when you define a sprite one row of a sprite is 1 byte of data right?  

 

5 hours ago, DZ-Jay said:

If you'd like to post some of your code

thank you..  ok i'll try to keep this concise..  in the twinkle twinkle audio example in the book.  while the music plays a dot randomly appears around the screen independent of the music..  it is expressed as i understand it like this:

 

WHILE 1  ' I can change this to a 9 it still works.  It just seems like WHILE (something) is here, do it.  
        c = RANDOM(240)
        PRINT AT c COLOR 7,"."
        FOR d = 0 TO 10
            WAIT
        NEXT d
        PRINT AT c," "
    WEND

 

twinkle_twinkle_little_star:

    DATA 20

    MUSIC D4,-,-
    MUSIC D4,-,-
    MUSIC A4,-,-
    MUSIC A4,-,-

 

(skipping ahead from space sake..)

 

    MUSIC E4,-,-
    MUSIC E4,-,-
    MUSIC D4,-,-
    MUSIC S,-,-

 

    MUSIC STOP

 

--- So maybe what I'm unclear on is how to actually change a variable.  none of the examples so far have changed a variable from one value to another other than through loops which was more for time delays..   I tried this:

 

a = 1   ' my addition

 

WHILE a = 1    ' declaring that a = 1 I would hope this means only do this so long as a does in fact equal 1
        c = RANDOM(240)
        PRINT AT c COLOR 7,"."
        FOR d = 0 TO 10
            WAIT
        NEXT d
        PRINT AT c," "
    WEND

 

twinkle_twinkle_little_star:

    DATA 20

    MUSIC D4,-,-
    MUSIC D4,-,-
    MUSIC A4,-,-
    MUSIC A4,-,-

 

(skipping ahead from space sake..)

 

    MUSIC E4,-,-
    MUSIC E4,-,-
    MUSIC D4,-,-
    MUSIC S,-,-

 

    MUSIC STOP

 

a = 2 ' thinking if I change the a = 1 to 2 then the loop would stop because a no longer = 1..  

 

5 hours ago, carlsson said:

using commands like DEFINE and SCREEN.

I can't wait to get into that!  

 

5 hours ago, carlsson said:

you could fit 15 full sets of either GRAM or screens

I am pretty sure my ideas could adapt to those constraints..  very exciting. 

 

5 hours ago, carlsson said:

heavily uses moving software sprites

like a game like bump n' jump or mission x?  

 

6 hours ago, DZ-Jay said:

That is a typical "infinite loop." 

good to know, but yea clearly i need to work on my loop syntax..  i'm sure i'll be doing more in chapter 4!

 

6 hours ago, DZ-Jay said:

If your syntax is wrong, the compiler would complain.

yep not complaining.. it's me.. 

 

5 hours ago, DZ-Jay said:

That is a practical technique, indeed, but doesn't come for free:  you've just traded time for space.

yep time is more precious than space for me at this point..  i'd sooner design smaller than force through something like that..  

 

5 hours ago, DZ-Jay said:

Here's an example of the Snowman's walking animation:

looking forward to going through this content soon..  been a bit hectic at work / on the road a lot.. but i still managed to do a few things.  thanks for sharing those examples!  

 

 

Link to comment
Share on other sites

Yes, the loop will run until a no longer equals 1. But the change needs to happen inside the WHILE - WEND loop, or at least in a GOSUB call that you place within that loop. Any change to the variable a that you place outside of the loop will make no change to the function.

 

Also I should add that it is good practice to put all your graphics data, music data etc at the very end of your program, after the executable code. While it is perfectly possible to GOTO to a label that follows after the data, it creates rather hard to follow programs. Whatever you do, never let the CPU run into any form of data since it will treat it like instructions and most likely crash out hard.

 

I try to keep the structure main code - subroutines - fixed values for initialization of variables - graphics data and screens - music data though the exact order doesn't matter as long as the end of your main code, you have somewhere to jump, most likely back to the beginning of your main code. You don't want to accidentally run into your first subroutine without having GOSUB'd there as it would also cause havoc once the program tries to the exit the subroutine.

 

Edit: And yes, a 16-bit word variable is twice the size of a 8-bit byte variable meaning you can store values up to 65535 into a single word.

 

Actually the GRAM definitions are packed into words where the most significant 8 bits equal line #2, and the least significant 8 bits are line #1. Then another word follows with lines #4 and #3, lines #6 and #5, lines #8 and #7. As long as you use BITMAP you don't have to worry about this, but if you would decide to define the bitmaps using DATA statements you would have to pack the data yourself. A program like Intycolor does this automatically when it creates a screen.

Edited by carlsson
  • Like 1
Link to comment
Share on other sites

1 hour ago, carlsson said:

inside the WHILE - WEND loop, or at least in a GOSUB call

i'll keep that in mind but don't know how to use gosub or how to do what you're saying, BUT i have a lot of examples in the book to go through so i'm sure it's going to teach that stuff soon.  I can't wrap my head around how i break a loop from inside the loop?  because it was started with a "1" and once i leave the loop won't the "1" state just fire off again?  answer might be in the pong demo i'm about to start.  

 

1 hour ago, carlsson said:

Actually the GRAM definitions

still working up to really comprehending much of this.  i believe i get it but haven't got a working knowledge yet but i look forward to exploring it!

 

1 hour ago, carlsson said:

never let the CPU run into any form of data

how do i stop that?  i mean doesn't the cpu see things like:

 

smiling_face:
    BITMAP "..XXXX.."

 

The CPU reads everything right?  

Link to comment
Share on other sites

A couple of things that may help:

 

  • The CPU will execute the program from top to bottom, in the order the statements appear.  If some of those statements happen to be data instead of actual code, the CPU won't know the difference.  To it, it is all binary numbers (what the compiler and assembler generate in the finally ROM), and it will try to interpret it as instructions.  If they are not valid instructions, the program will crash.
     
  • Exceptions to the above top-down rule is any statement that alters the flow of the program, so called "flow control" statements.  These are things like GOTO and GOSUB, which branch to other areas; and IF/ELSE, which induce the CPU to execute one block of code over another, conditionally.

    Also, included in this category are loop constructs, like FOR/NEXT or WHILE/WEND, which essentially cause the CPU to jump back to the start of the loop and execute the block until some condition is met.
     
  • A WHILE loop will continue looping until the conditional expression evaluates to FALSE -- essentially, it means "while x is true, do something," which implies that when "x" is no longer true, the loop will stop.

    In IntyBASIC, the value zero is treated as logical FALSE, and any non-zero value is treated as logical TRUE.  This is why "WHILE 1" or "WHILE 9" work identically: both 1 and 9 are non-zero values, so they are treated as TRUE, and therefore will cause the loop to continue repeating eternally, since the literal constants will never change.
     
  • The conditional expression in a WHILE loop can be any valid IntyBASIC expression.  This includes literal constant values (like 1 or 9), as well as more complex logical or arithmetic expressions like "a = 1," etc.

    Arithmetic expressions will evaluate to either zero or non-zero values, and therefore treated as FALSE or TRUE, respectively.  Logical expressions will evaluate to logical TRUE or logical FALSE values.  (Internally, these are merely the values -1 for TRUE, and zero for FALSE, but you shouldn't have to worry about that.)
     
  • If the program flow enters an infinite loop, the only way for it to escape it is for the loop condition to change while the loop is executing.  This is why your program doesn't behave as you expect:  Your attempt to change the value of "a" occurs outside the loop itself, and because the CPU is repeating the loop over and over and over, it never gets outside to see that statement.
     
  • Notwithstanding the above, consider that if you just move the "a = 2" into the loop, it will cause the loop to end as soon as that statement is encountered.  That means that it will probably just run through the loop once, encounter the variable change, and quit as soon as it checks the value of "a" at the top of the loop on the next iteration.  In other words, it will just run once instead of repeating.  That may or may not be what you wanted, but it is important to know.
     

I hope his helps.

 

   dZ.

Edited by DZ-Jay
Link to comment
Share on other sites

3 minutes ago, DZ-Jay said:

never gets outside to see that statement.

now i understand that.  

 

4 minutes ago, DZ-Jay said:

it will probably just run through the loop once

I follow this as well..  i think..  testing.. and..  i guess i need to figure out how to properly insert a condition in the loop like a > 0..  my thinking is that when the song hits the end it changes the variable to 0 (false) and then the next time the WHILE runs through and confirms that at any particular loop of WHILE a is no longer greater than zero..  and that might break the loop but my expression is not compiling right..  

 

WHILE a = 1
        c = RANDOM(240)
        PRINT AT c COLOR 7,"."
        FOR d = 0 TO 10
            WAIT
        NEXT d
        a = > 0.    ' this is my addition
        PRINT AT c," "
    WEND

 

twinkle_twinkle_little_star:

    DATA 20

    MUSIC D4,-,-
    MUSIC D4,-,-
    MUSIC A4,-,-
    MUSIC A4,-,-

    a = 0     ' this is where the event would "break" the loop in my mind at least..  intybasic doesn't agree.  

    MUSIC STOP
 

 

 

Link to comment
Share on other sites

Hm, won't that generate a compiler error? You are assigning the variable a the value of "larger than zero".

 

Something like this would work:

 

WHILE 1 : REM This is your outer, infinite loop that hopefully prevents the game from crashing
 WHILE a<>0 : REM This is an inner loop, perhaps a title screen but could also the main game logic
    c = RANDOM(240)
    PRINT AT c COLOR 7,"."
    FOR d=0 TO 10:WAIT:NEXT d
    a = (c>10) : REM See below
    PRINT AT c," "
  WEND
WEND : REM Here ends your infinite loop, assuming you want a game that can be replayed without resetting the machine

REM If you want the console to get stuck at doing nothing, use this infinite dummy loop
WHILE 1:WEND

music_data: REM blah blah

 

The line a = (c>10) means that the CPU will evaluate if your random number 0-239 is larger than 10. If it is, a will have a truth value (non-zero) and the loop continues. As soon as the random number c is in the range 0-10, the variable a will be set to 0 (false) and subsequently, the WHILE loop will exit and rest of your program follows.

 

Perhaps a more typical use case for the inner loops would be this:

 

WHILE CONT.BUTTON=0 : REM wait for the user to press a button
  [ do things ]
WEND

WHILE CONT.BUTTON:WEND : REM wait for the user to release the button

 

Regarding waiting for the song to end, there is an existing system conditional called MUSIC.PLAYING that evaluates to true until the music player has reached MUSIC STOP. It means if you want to plot stars until the song is over, you would use WHILE MUSIC.PLAYING and then make sure that once you exit that loop, you have somewhere to go (at least an infinite dummy loop since you don't want the CPU to treat data as if it was code).

 

Also: You must not include code as part of the music data, or for that matter graphics data. The CPU will indirectly read it as part of the music data, though I don't know how the music player routine will parse the "a=0" or if it generates a compiler error.

 

For advanced usage, there are memory locations that will contain the current row of music which you could PEEK unless checking for MUSIC.PLAYING is not enough. I've toyed with this before but not done anything practical with it. However that is the advanced course and probably not what you want right this minute.

Edited by carlsson
  • Like 1
Link to comment
Share on other sites

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...