Jump to content

Grebnedlog

Members
  • Content Count

    31
  • Joined

  • Last visited

Posts posted by Grebnedlog


  1. I can't say for sure, but I'm betting it's the MAMCR functionality of the ARM emulation. This was addressed in version 3.5, which contained the following release notes:

    • Added MAMCR handling to the Thumb ARM emulation code. Note that MAMCR isn't actually emulated, it is just ignored for now. This fixes a bug whereby accessing MAMCR would crash the ARM emulation.
    • Added 'thumb.trapfatal' commandline argument, which causes the Thumb ARM emulation to either trap on a fatal error (throw an exception to the debugger and exit emulation) or simply log the error and continue. This should normally always be enabled, but can be disabled by developers for testing reasons.

    Stella version 3.4.1 is very old. The current release is now at version 3.7.2, with 3.8 coming out within the month (or so). I would suggest always upgrading to the latest version before reporting bugs.

     

    Ah, sorry. I actually did have 3.7.2 installed, but the for some reason the Visual bB devkit program I was using was mapped to an archived version when I took the screenshot.

     

    In any case, the ARM error still seems to occur when I run it with Stella 3.7.2 (see attached JPEG).

     

    Also, sorry to be a pest, but what would the syntax be to turn off the trap? Thanks.

    post-33796-0-34534400-1350149659_thumb.jpg


  2. What do routines like this really need to do?

     

    The examples here are writing chunks. If you don't need

    to do things on a per bit basis it's a lot easier (and faster)

    to do bytes or rows.

     

    I agree, it would be nice to think of other applications for this. My application was very specific and limited (loading hi-res playfields for DPC+ games without using the graphics bank).

     

    I guess that bit arrays might also work pretty well for storing a bunch of scrollable playfield data too, but not using the specific pf-drawing routine I wrote. That works fine for drawing a static playfield before UI starts, but it's too cycle intensive to nest in any sort of looping gameplay. In general, I guess the application would be that storage of any binary data that requires >256 values. But I'm thinking binary values would probably be most useful for storing playfield and sprite pixel states -- and, as far as I know, there is no "playerpixel" command for writing to player sprites, so storage of playfield data is probably the most applicable thing for most kinds of Atari games.

     

    As for including this on Random Terrain's bB page, what exactly is it that needs to be up there? Is it just a brief explanation of how to structure a bit array and read values from it? If that's the case, are we sure that the method we've come up with on this thread is the simplest/most-efficient one? It works well, but I'm just wondering about other ways to do it (and other ways to demonstrate it).


  3. Does anyone here know enough about how ARM emulation works in Stella to explain what this recurring crash message means (attached JPEG), and how one might go about troubleshooting it in a program? Are there instructions or methods that other programmers have found to generally cause these kinds of errors?

    post-33796-0-12908400-1350076689_thumb.jpg


  4. WritePFChunk
    for current_row = 0 to 7
    lo_pointer = current_row * 4
    print_row = chunk_start + current_row
    for current_col = 0 to 31
    current_bit = current_col & 7
    current_byte = current_col / 8 + lo_pointer
    
    on maze_ref goto MazeData1 MazeData2 MazeData3 MazeData4
    MazeData1
    current_byte = Mazes1[current_byte] : goto Continue_WritePFChunk
    MazeData2
    current_byte = Mazes2[current_byte] : goto Continue_WritePFChunk
    MazeData3
    current_byte = Mazes3[current_byte] : goto Continue_WritePFChunk
    MazeData4
    current_byte = Mazes4[current_byte] : goto Continue_WritePFChunk
    
    Continue_WritePFChunk
    
    if current_byte & setbits[current_bit] then pfpixel current_col print_row on
    next
    next
    

     

    Yes that is better, thanks.


  5. How could you select amongst data statements with a parameter?

    Only thing I can think of is a case statement. (or IF statements)

     

    Yeah, that's what I meant. You could do it with cases or conditionals.

     

    It was sort of a broad question (whether this could be adapted for random mazes). The short answer is "of course it can", but it can be done in almost too many ways to describe. In addition to randomizing the pointer, you could also assign another byte of RAM that points to different IF statements. For instance:

     

     dim current_row = a
     dim current_col = b
     dim current_byte = c
     dim current_bit = d
     dim lo_pointer = e 
     dim print_row = f 
     dim chunk_start = g
     dim maze_ref = h
    
    
    ...
    
    
    WritePFChunk
    for current_row = 0 to 7
       lo_pointer = current_row * 4
       for current_col = 0 to 31
          current_byte = current_col / 8 + lo_pointer
          current_bit = current_col & 7
          print_row = chunk_start + current_row
         on maze_ref goto MazeData1 MazeData2 MazeData3 MazeData4
    MazeData1
         if mazes1[current_byte] & setbits[current_bit] then pfpixel current_col print_row
         goto Continue WritePFChunk
    MazeData2
         if mazes2[current_byte] & setbits[current_bit] then pfpixel current_col print_row on
         goto Continue WritePFChunk
    MazeData3
         if mazes3[current_byte] & setbits[current_bit] then pfpixel current_col print_row on
         goto Continue WritePFChunk
    MazeData4
         if mazes3[current_byte] & setbits[current_bit] then pfpixel current_col print_row on
    Continue WritePFChunk
         next
      next
    

     

    How he arrives at the value of "maze_ref" is completely up to the programmer, of course. It could perhaps increment with the levels or stages that a player advances through, or could itself be randomly assigned.

     

     

    EDIT: Boy, this forum software really messes up the spacing inside CODE tags.


  6. So can any of this be used with the regular version of bB? Like a 23 row superchip playfield?

     

    I see no reason why it couldn't be used with any kernel version. The routine isn't doing anything that's specific to the DPC+ kernel. The only reason I picked that one is because that's the kernel I'm working with at the moment, and because I think it's greatest usefulness would be with drawing hi-res playfields that eat up a lot of ROM space.

     

    If so, can it be used to draw different sections of the screen by randomly selecting from little predetermined chunks of data and do something similar to this:

     

    http://www.atariage....maze-test-2011/

     

    random_maze_test_16x16x16_with_scroll_32x23_2011y_08m_21d_2001t.bin

     

    (Hit the reset switch to create different mazes.)

     

    Again, I don't see why not. For instance, you could just define offsets that point to the various regions of the maze, then randomize which segment of the array it reads during the pfpixel routine.

     

    For instance, when using this method each row of playfield pixels is defined by 4 bytes, meaning that each data statement can contain 64 playfield rows (or one 64 row x 32 column playfield). So, if you were using the optional superchip 23 visible rows (23 x 32) display, you could maybe break each maze down into 4 segments of 16 rows (or 8 segments of 8 rows, etc), then do a rand command in conjunction with "current_row" to pick the starting point of the segment you want to draw.

     

    And that's just one of many ways to do it. I see no reason to even be limited to a single data statement to draw a semi-random "maze-style" playfield. You could always look up data segments in multiple arrays for your maze pieces, in whatever way you see fit. All this routine does is draw whatever binary image is fed into it.


  7. What release number of the DPC+ kernel are you using? I am using the version from January 2011.

     

    set kernel DPC+
    set kernel_options collision(playfield,player1)
    set optimization inlinerand
    set smartbranching on
    set tv ntsc

     

     

    Above is what the first few lines of your code say in both BAS files. Is that a typo? I am still new to using DPC+ ,so I don't know.

     

    I tried both of the BAS files posted but the compilation fails. I changed around the kernel options but then it was looking for pfcolors, then bkcolors..

     

    Any help to get it to compile is welcome. :)

     

     

    Is what a typo? Not sure I understand your question, but I'm using bB version 1.1d.


  8. @bogax

     

    Okay, I see the problem. The elements in your setbits array were just in reverse order. Changed it to this and it works fine now:

     

     data setbits
    %10000000, %01000000, %00100000, %00010000,
    %00001000, %00000100, %00000010, %00000001
    end

     

    Thanks again! I think this could be very useful for hi-def playfield drawing.

     

    EDIT:

    Attached a BAS file combining all edits and corrections.

    draw_pf_from_binary_array.bas


  9. That might do it but then you need to intialize

    lo_pointer

     

    Your rows are going to be addressed as 0-7

     

    Oh, okay. Got it now.

     

    I can try but you probably want someone who knows what they're doing ;P

     

    Ha! Based on that other thread, I'm fairly sure you know what you're doing. Now I just want to be sure that I know what you're doing. :)

     

    I'd imagine it something like this:

     

    dim current_row = a
    dim current_col = b
    dim current_byte = c
    dim current_bit = d
    dim print_row = e
    dim chunk_start = f
    
    chunk_start = 20
    
    
    PROGRAMLOOP
    DF0FRACINC=128
    DF1FRACINC=128
    DF2FRACINC=128
    DF3FRACINC=128
    DF4FRACINC=255
    DF6FRACINC=24
    if joy0fire then z{0} = 1
    if !joy0fire && z{0} then gosub WritePFChunk
    drawscreen
    goto PROGRAMLOOP
    
    
    WritePFChunk
    for current_row = 0 to 7
    for current_col = 0 to 31
    current_byte = current_col / 8 + lo_pointer[current_row]
    current_bit = current_col & 7
    print_row = chunk_start + current_row
    if hellodata[current_byte] & setbits[current_bit] then pfpixel current_col print_row on
    next
    next
    
    z{0} = 0
    
    return thisbank
    
    
    bank 3
    
    bank 4
    
    bank 5
    
    bank 6
    
    data lo_pointer
    0, 4, 8, 12, 16, 20, 24, 28
    end
    
    data hellodata
    %00000010,%01011101,%00010001,%11000000
    %00000010,%01011101,%00010001,%01000000
    %00000010,%01010001,%00010001,%01000000
    %00000011,%11011101,%00010001,%01000000
    %00000011,%11011101,%00010001,%01000000
    %00000010,%01010001,%00010001,%01000000
    %00000010,%01011101,%00010001,%01000000
    %00000010,%01011101,%11011101,%11000000
    end
    
    data setbits
    %00000001, %00000010, %00000100, %00001000
    %00010000, %00100000, %01000000, %10000000
    end
    

     

    I used a look up table for lo_pointer because it

    only costs a couple bytes, doesn't use a variable

    and is faster

     

    edit: ack! wrong! it's significantly slower

    (forgot that moves it into the inner loop)

     

    so using a variable:

     dim current_row = a
    dim current_col = b
    dim current_byte = c
    dim current_bit = d
    dim lo_pointer = e
    dim print_row = f
    dim chunk_start = g
    
    chunk_start = 20
    
    
    PROGRAMLOOP
    DF0FRACINC=128
    DF1FRACINC=128
    DF2FRACINC=128
    DF3FRACINC=128
    DF4FRACINC=255
    DF6FRACINC=24
    if joy0fire then z{0} = 1
    if !joy0fire && z{0} then gosub WritePFChunk
    drawscreen
    goto PROGRAMLOOP
    
    
    WritePFChunk
    for current_row = 0 to 7
    lo_pointer = current_row * 4
    for current_col = 0 to 31
    current_byte = current_col / 8 + lo_pointer
    current_bit = current_col & 7
    print_row = chunk_start + current_row
    if hellodata[current_byte] & setbits[current_bit] then pfpixel current_col print_row on
    next
    next
    
    z{0} = 0
    
    return thisbank
    
    
    bank 3
    
    bank 4
    
    bank 5
    
    bank 6
    
    
    data hellodata
    %00000010,%01011101,%00010001,%11000000
    %00000010,%01011101,%00010001,%01000000
    %00000010,%01010001,%00010001,%01000000
    %00000011,%11011101,%00010001,%01000000
    %00000011,%11011101,%00010001,%01000000
    %00000010,%01010001,%00010001,%01000000
    %00000010,%01011101,%00010001,%01000000
    %00000010,%01011101,%11011101,%11000000
    end
    
    data setbits
    %00000001, %00000010, %00000100, %00001000
    %00010000, %00100000, %01000000, %10000000
    end
    

     

    damn! more edits:

    should be

    current_byte = current_col / 8 + lo_pointer

     

    Thanks! The resulting binary looks close to correct. However, instead of saying "HELLO", my screen looks like this:

     

    post-33796-0-86920700-1349390051_thumb.jpg

     

    I believe that's Klingon for "Destroy all humans" ;)

     

    Seriously, though, I guess it looks like it's reading some of the data in backwards, and starting to write it in the middle of the screen. Any ideas?

     

    EDIT:

    Oh, I also forgot to mention that bB cannot see data in different banks from the one that is reading them, so I cut and pasted the arrays back into bank 2 with the WritePFChunk routine (though, I suppose, you could alternately stick the routine in bank 6, and then bankswitch to it from the main loop.)


  10. No offence taken. But, I'm still not sure how the extra cycles needed for loops and taking the more indirect approach of DATA statements help.

     

    Well, I guess the idea is a based on a tradeoff. In this case, the tradeoff is between hi-res playfield definitions and hi-res sprite definitions. Both share the same bank in the DPC+ framework, so if you want more of one, you'll necessarily have less of the other. If I wanted to have 88-row multicolored playfields (which I do) and had to rely solely on using the static playfield definitions, I wouldn't be able to include very many of them, and won't be able to include lots of sprite data either. Live playfield drawing seems far more useful in general for hi-res screens, but particularly if you want to have lots of varying kinds of sprites.

     

    From what I can see, the loop statement I used isn't really using that many more cycles than a string of successive static pfpixel commands would (and the screen would roll for either version, if you don't take precautions). Also, your version uses 1650 bytes of ROM, and to draw only 11 rows in one static position. My version draws 8 rows wherever I want them, and only uses 373 bytes (256 of which is the data array itself, and the other 117 of which can be reused to draw multiple screens) and it will use far less still if we can get binary arrays working.

     

    Actually, that would be really exciting... if that was the case, a single data statement could draw a full, fairly high resolution screen without sacrificing any space for sprite data.


  11. You could straight up use code to avoid DATA statements and complicated for next loops.

    pfpixel 1 1 on : pfpixel 2 1 on : pfpixel 3 1 on : pfpixel 4 1 on : pfpixel 5 1 on : pfpixel 3 2 on : pfpixel 3 3 on : pfpixel 8 3 on : pfpixel 9 3 on : pfpixel 10 3 on : pfpixel 11 3 on : pfpixel 3 4 on
    pfpixel 8 4 on : pfpixel 27 4 on : pfpixel 28 4 on : pfpixel 3 5 on : pfpixel 8 5 on : pfpixel 9 5 on : pfpixel 15 5 on : pfpixel 16 5 on : pfpixel 17 5 on : pfpixel 27 5 on : pfpixel 28 5 on : pfpixel 8 6 on
    pfpixel 14 6 on : pfpixel 20 6 on : pfpixel 21 6 on : pfpixel 22 6 on : pfpixel 23 6 on : pfpixel 24 6 on : pfpixel 27 6 on : pfpixel 28 6 on : pfpixel 8 7 on : pfpixel 9 7 on : pfpixel 10 7 on : pfpixel 11 7 on
    pfpixel 15 7 on : pfpixel 16 7 on : pfpixel 22 7 on : pfpixel 27 7 on : pfpixel 28 7 on : pfpixel 17 8 on : pfpixel 22 8 on : pfpixel 14 9 on : pfpixel 15 9 on : pfpixel 16 9 on : pfpixel 22 9 on : pfpixel 27 9 on
    pfpixel 28 9 on : pfpixel 22 10 on

     

    No offense intended, but I'm not sure why would that be better than my nested loop statement. I mean, both our versions work, but your version seems like it would be a nightmare for drawing lots of pictures with. Design workflow for my version would just involve drawing a playfield in the ordinary way (either by using tools or typing it out ASCII style), using find-replace to comma separate, copying it into a data array (in the bank of my choosing), and having the program run the routine whenever I need to draw or redraw a section of the playfield.

     

    Also, my version allows the programmer to vary the position (vertical only, right now, but probably easily adaptable for horizontal) of the playfield graphic being drawn. For instance, with my V2 version, you can change the message from "HELLO WORLD" to "WORLD HELLO" simply by changing "chunk_start = 20" to "chunk_start=70", whereas your static version would require recoding all the pfpixel statements to achieve the same effect (essentially doubling the ROM space used, too).

     

    The only thing to watch out for is going over your CPU cycles so the screen starts to roll. The easy way out is to break up your pfpixel commands with an appropriate DRAWSCREEN somewhere.

     

    Actually, for the particular project I had in mind this wouldn't be a problem, since the drawing routine doesn't happen during gameplay, but rather before a new game level starts (i.e. setting up the game map, obstacles, etc). I essentially shut off the display while this is going on by reducing the screen resolution to 1 until the process is finishes, meaning the screen won't appear to roll even if the improper number of scanlines are drawn (which, they most definitely will be). I've tested this on real hardware and it works pretty much as expected. The screen goes black for a second while the drawing is done, and then I increase the screen res just before the level starts.

     

    Also, normal use means expecting temp vars to look, feel and taste like normal vars. You can't expect the values to hold. You can't expect the calculations to actually happen. Just don't use them. Trust me.

     

    Well, I guess we'll have to agree to disagree on that one. I personally am finding the temp vars indispensable for certain in-game routines (particularly for things like soft collisions, where a temp can act as a second "edge" for a sprite coordinate during an overlap test). It's true they aren't useful as general purpose variables (seing as they are temporary), but not using them at all seems a little extreme.


  12. I phrased that poorly

     

    Suppose you set lo_pointer = 15 (some arbitrary value)

    then call WritePFChunk

     

    then the first time you run the current_col

    loop current_row = 0 and lo_pointer = 15

    at the end of the first pass through the

    current_row loop lo_pointer will get set to 0

    ie 0 * 32 so your passes would go like this

     

    current row = 0, lo_pointer = 15

    current row = 1, lo_pointer = 0

    current row = 2, lo_pointer = 32

    current row = 3, lo_pointer = 64

    current row = 4, lo_pointer = 96

    current row = 5, lo_pointer = 128

    current row = 6, lo_pointer = 160

    current row = 7, lo_pointer = 192

    current row = 8, lo_pointer = 224

     

    9 iterations of the current row loop

    the first one with what ever lo_pointer is

    when you call WritePFChunk

     

    Okay, I think I see what you mean. If so, then yes you are right that it is the wrong number of iterations. I changed it to "for current_row 1 to 8." Thanks!

     

    Is there any chance you can help with converting this to a binary bitmap routine?


  13. possibly I misunderstand your intent.

     

    On your first pass through the inner for loop

    current_col will be 0 and lo_pointer will be whatever

    you haven't set lo_pointer yet

    At the end of the first pass through the loop

    you'll set lo_pointer to current_col * 0

    and lo_pointer will be 0 while current_col is 1

    (second pass). etc

    also you'll make 9 passes through the loop

    (0-8 inclusive)

     

    If you multiply by a power of two that's 8 or less

    Bb will use shifts so * 8 * 4 compiles as shifts

    * 32 calls the mutiplication routine

     

    When lo_pointer is zero, the routine is searching the array values representing the first row in the "playfield chunk" (i.e. the segment of the playfield being drawn). The lo_pointer advances by 32 on each iteration to draw the next playfield row, starting with playfield position 0 and advancing to position 31. The routine checks the value, then draws a pixel if it reads a "1".

     

    As RevEng and theloon pointed out above, this routine would obviously be a lot better (and more useful) if the array data could be read as a binary array, since only on/off states are needed. I'm fighting my way through the binary array examples you provided on that other thread, but I'm not sure how to adapt it to this purpose. Any help would be much appreciated.


  14. As I understand it Batari's stated plan is to only allow graphic data like playfields access the extra storage space. He said maybe on allowing use for SDATA and was even less enthusiastic about normal DATA statements (which is what I'd want it for most).

     

    So, if I got my info right, just using normal playfield statements sounds like the way forward. That being said, why not just use consecutive pfpixel statements and call it a day?

     

    Well, I guess the point of the experiment is to maximize the graphic storage space for something other than playfield data (for instance, the project I'm working on requires the use of a lot of sprite data, and uses 88 rows of playfield pixels. So dynamically drawing certain portions of the playfield without storing that data in the graphics bank is actually pretty helpful to me. Not sure what you mean by "consecutive pfpixel statements" (from what I can tell, that's what I'm doing with my for-loop in the post above).

     

    Also, what RevEng said. My opinion is that temp vars are too unpredictable for normal use. i actually "waste" one or two normal vars for temp usage.

     

    Again, I'm not really sure what you mean by "normal use" here. They can't be used to store persistent data, but I wasn't trying to use them that way in my example. They do seem to have a few quirks that weren't readily apparent. For instance, I'm still not sure why the temp vars are obliterated after a pfpixel, but I know that I haven't had any problem using them to draw pixels in an un-nested for-next loop... well, not so far, at least. ;) The problem only seemed to arise when I included them in a nested loop. Perhaps RevEng could explain why that is.

     

    Also, once more, are you using each 8-bit data statement element as one playfield pixel? I didn't have time to figure out if you were. If so, I'd suggest using each of the 8 bits in an element as playfield pixels.

     

    The best way to slim it down (as theloon suggested) is to convert your data to use binary representation instead of setting bytes to 0's and 1's. (eg. %11001101 would replace 1,1,0,0,1,1,0,1,...) Each screen will go from using 256 bytes to using 32 bytes.

     

    You know, I tried following the example in this post, but I confess I got a bit lost (Get it? A bit lost? :D). I guess part of the reason is that I'm not sure what the binary posted there is supposed to be doing. Maybe one of you can edit my v2 BAS to demonstrate how it would be converted to a binary array and drawn from my routine? I took the liberty of comma-separating the "hellodata" statement, to remove some of the grunt work for you:

     

     %00000010,%01011101,%00010001,%11000000
    %00000010,%01011101,%00010001,%01000000
    %00000010,%01010001,%00010001,%01000000
    %00000011,%11011101,%00010001,%01000000
    %00000011,%11011101,%00010001,%01000000
    %00000010,%01010001,%00010001,%01000000
    %00000010,%01011101,%00010001,%01000000
    %00000010,%01011101,%11011101,%11000000

     

    There isn't a way in pure bB to pass on a reference to an array. (or any variable)

     

    Oh, OK. Is that because the assembled code auto-labels the jump tables during compilation?

     

    How many screens worth of data are we talking about? If you convert to binary representation and it's 8 or less you could fit them all into a single data statement, and just offset which row you begin with to access them individually. If it's more, then you need to convert to using sdata.

     

    Well, I suppose I was only thinking of about twelve (partial) screens for the particular project I was working on, but obviously more (and smaller) is always better, and drawing the pf using a bit array with offsets would be useful for all sorts of projects, I would think.

     

    Thanks to both of you for your help.


  15. pfpixel and similar functions obliterate temp1, temp2, and temp3, which is probably why you're having trouble with the looping and getting ARM exceptions.

     

    Aha! Thanks so much, that indeed seems to be the trouble. :)

     

    With that in mind, this version already looking a lot more streamlined, and saving some precious bytes:

     

    dim current_row = a
    dim current_col = b
    dim lo_pointer = c
    dim current_pixel = d
    dim print_row = e
    dim chunk_start = f
    
    chunk_start = 20
    
    
    PROGRAMLOOP
    DF0FRACINC=128
    DF1FRACINC=128
    DF2FRACINC=128
    DF3FRACINC=128
    DF4FRACINC=255
    DF6FRACINC=24
    if joy0fire then z{0} = 1
    if !joy0fire && z{0} then gosub WritePFChunk
    drawscreen
    goto PROGRAMLOOP
    
    
    
    data hellodata
    0,0,0,0,0,0,1,0,0,1,0,1,1,1,0,1,0,0,0,1,0,0,0,1,1,1,0,0,0,0,0,0,
    0,0,0,0,0,0,1,0,0,1,0,1,1,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,
    0,0,0,0,0,0,1,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,
    0,0,0,0,0,0,1,1,1,1,0,1,1,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,
    0,0,0,0,0,0,1,1,1,1,0,1,1,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,
    0,0,0,0,0,0,1,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,
    0,0,0,0,0,0,1,0,0,1,0,1,1,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,
    0,0,0,0,0,0,1,0,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0
    end
    
    
    WritePFChunk
    for current_row = 0 to 8
    for current_col = 0 to 31
    current_pixel = lo_pointer + current_col
    print_row = chunk_start + current_row
    if hellodata[current_pixel] = 1 then pfpixel current_col print_row on
    next
    lo_pointer = current_row * 32
    next
    
    z{0} = 0
    
    return thisbank
    
    

     

     

    That said, I'm wondering if there's a way to slim it down even more?

     

    Also, now I'm starting to wonder in general if there's a way to reuse the same routine with variable data statements in bB, but without hard coding the name of the set each time. In other words, could the line:

     if hellodata[current_pixel] = 1 then pfpixel current_col print_row on

    be expressed such that "hellodata" is replaced with a variable that points to one of 256-byte several tables in ROM (i.e. "goodbyedata", "endofdata", etc.)? Or would that line have to be repeated for each table name?

     

    EDIT: Ugh, the site screwed up my code formatting a bit, so I attached the new BAS and BIN

    draw_pf_from_array_v2.bas

    draw_pf_from_array_v2.bas.bin


  16. I've been trying to write an elegant loop statement that can rewrite chunks of longer playfields from data statements, but I've been failing a lot more than I planned to. 8)

     

    Basically, the attached program writes 256 consecutive bytes of the playfield using the pfpixel command and a data statement (the idea here was to conserve some romspace in the graphics bank of DPC+ programs by defining some playfield data in other banks, and I'm assuming - maybe wrongly - this is the best way to do it.) The write-routine works, but it's too expensive in ROM to be useful right now (705 bytes):

     

    data objectdata
    0,0,0,0,0,0,1,0,0,1,0,1,1,1,0,1,0,0,0,1,0,0,0,1,1,1,0,0,0,0,0,0,
    0,0,0,0,0,0,1,0,0,1,0,1,1,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,
    0,0,0,0,0,0,1,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,
    0,0,0,0,0,0,1,1,1,1,0,1,1,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,
    0,0,0,0,0,0,1,1,1,1,0,1,1,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,
    0,0,0,0,0,0,1,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,
    0,0,0,0,0,0,1,0,0,1,0,1,1,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,
    0,0,0,0,0,0,1,0,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0
    end
    
    
    WritePFChunk
    for temp1 = 0 to 31
    if objectdata[temp1] = 1 then pfpixel temp1 current_row on
    temp2 = temp1 + 32 : temp3 = current_row + 1
    if objectdata[temp2] = 1 then pfpixel temp1 temp3 on
    temp2 = temp1 + 64 : temp3 = current_row + 2
    if objectdata[temp2] = 1 then pfpixel temp1 temp3 on
    temp2 = temp1 + 96 : temp3 = current_row + 3
    if objectdata[temp2] = 1 then pfpixel temp1 temp3 on
    temp2 = temp1 + 128 : temp3 = current_row + 4
    if objectdata[temp2] = 1 then pfpixel temp1 temp3 on
    temp2 = temp1 + 160 : temp3 = current_row + 5
    if objectdata[temp2] = 1 then pfpixel temp1 temp3 on
    temp2 = temp1 + 192 : temp3 = current_row + 6
    if objectdata[temp2] = 1 then pfpixel temp1 temp3 on
    temp2 = temp1 + 224 : temp3 = current_row + 7
    if objectdata[temp2] = 1 then pfpixel temp1 temp3 on
    next

     

    I might have some sort of basic brain problem here... this doesn't seem like such a complex task. I've tried to do it with nested for-loops and pointers, but these approaches either don't work as expected or cause a fatal ARM exception. Essentially, I need to advance the data pointer by 32 elements eight times using the fewest bytes possible, and I know the above method is pretty dumb. Can anyone help out?

    draw_pf_from_array.bas.bin

    draw_pf_from_array.bas


  17. DPC+ isn't exactly my area of expertise, but I'll give it a whack.

     

    When you issue a player1color: command in a DPC+ kernel, the assembly generated looks like this...

     

    lda #<(playerpointers+18)
    sta DF0LOW
    lda #(>(playerpointers+18)) & $0F
    sta DF0HI
    
    LDX #<playercolorL01_1
    STX DF0WRITE
    LDA #((>playercolorL01_1) & $0f) | (((>playercolorL01_1) / 2) & $70)
    STA DF0WRITE
    

     

    ...and a table gets stored in the kernel bank with the data. In this case, the data table is named "playercolorL01", but it's an auto-generated label, so you can't rely on that.

     

    The first two lda+sta pairs tell DPC+ which type of table we're storing. (player1=0, ..., player1color=18, ...) and the next two lda+sta pairs tell DPC+ where the data is.

     

    You may also be interested in a previous post I made with a routine to copy player0: data to the other DPC players. The routine itself isn't all that useful, as batari later added the same functionality in bB, but it may give you some insight into how the pointers work. In DPC, player0 data is stored like the standard bB kernel, and the virtual players use the funky DPC stuff.

     

    Also (if you haven't been looking at it) I find the assembly code generated by compiling a bB program is a good way to figure out what its doing.

     

    Thank you. I read your routine and it makes sense to me. I've been able to use it to copy player0 to a virtual sprite, but I'm wondering if it is possible to dynamically copy one virtual p1's data to another, without using the static labels bB assigns to the low pointers (i.e. "playerL0xxx_1") ?


  18. How about using the ball for collision detection? Place the ball over the area the object may collide with next, perform the collision routine and use the results.

     

    Yes, that's what I was thinking of as a workaround, too; flickering the ball under each sprites and then testing for those collisions for the gaps. If that was the case, the native Y-temp4 return would probably work okay if limited to the wall detection (turned off when within range of the ladder objects). It would be nicer to have sprite collisions and preserve the ball object, obviously, but that method would probably mimic the effect pretty well.


  19. What SeaGtGruff said about my "unreliable" comment is spot on. Sorry about mentioning soft collision and leaving you guessing. My thought was to use DATA statements as a collision map for the playfield. I opened a topic before to better understand how to create a binary array specifically for this purpose. Sadly, despite incredible help, I'm still working on it :)

    http://www.atariage....s-binary-array/

     

    Interesting thread! That would be a good workaround for the absence of pfread, but I think it might be a bit of overkill for the types of games I'm imagining here. For example, in my demo I don't need the to id the state of every drawn pixel on the screen, just the ones that will trigger certain events. Although that problem would also be solved with a binary array, I think it's possible to solve with byte arrays, too, depending o the complexity of the hitzone shape. For example, I might have a craggy, mountainous shape on the screen composed of 264 playfield pixels, but for the purposes of in-game collision detection my x-y collision map for it might be far simpler. I might only have to check a few rectangles, or a simple square/line.

     

    I did get Batari's original Rally-X example to work and he uses a DATA array for playfield collisions but the code doesn't make sense to me

    http://www.atariage....ll-examplegame/

     

    Hmm... I can't get this one to compile (I'm using 1.1d).


  20. Thanks for the advice and insights on assembly outputs. Works like a charm!

     

    Actually, it might be possible to solve the problem a different way, by checking the x position of each sprite and stopping it (or reversing its direction) when it gets to an x position where you know it will collide with the playfield, rather than trying to use the collisions for that. If the game has multiple screens where the ladders are in different locations then you'll need to vary the checks to account for the different x positions of the ladders, but you could perhaps use a variable for that instead of a literal. For example, after you draw the new screen you could set ladder1x to the x postion of the ladder on level 1, then ladder2x, then ladder3x, and compare the sprites' x positions to the x position of the ladder for whichever level they're on.

     

    I think I grok you here. I guess that could work for a handful of repeating screens that repeats the same collision areas (something like "Donkey Kong" springs to mind). If I grok you right, that's already in the demo program, in a limited way (the sprites shift direction when the reach a minimum/maximum X near the screen edge. I just get the feeling that might be a bit much to store in RAM. For instance, even the very sparsely populated demo program has six such collision zones -- it wouldn't be the ladders that would need to be checked, but the pits and walls.

     

    I was wondering if there could be a more general approach. Still, I guess that technique could work fine for certain games. Maybe instead of tracking all the collision zones constantly, we could loop some pointers through an array that contains all the x-y collision zones for that "game screen." The pointer would advance one frame at a time, then check to see if any of the virtual sprites is overlapping that particular collision zone. It might look a little visually sloppy maybe, with sprites constantly "overstepping" gap zones and clipping into wall zones that haven't come up in the pointer queue yet, but I guess it might save some precious RAM.

     

    But gosh-golly, this still seems like it be a whole lot simpler with pfread implemented! :) I wonder if there are any plans to do eventually so (or if it's even possible, given all that's going on already in this kernel).

     

    Thanks again.


  21. I apologize if my previous post frustrated you--

     

    No, not at all. I was just worried I wasn't explaining my questions right (and still am, sort of). Thank you very much for the detailed reply.

     

    my comment about the temp variables being used in other routines besides drawscreen was mainly in response to what theloon said about them being "unreliable." In my own experience they're safe to use as long as you don't expect them to keep their values after calling drawscreen, but it also depends a great deal on what other things are going on in your program.

     

    That's kind of what I thought. For instance, in the program I was using them to draw the hit zones for the ladders (what I assume theloon meant by "soft collisions), and it seemed to work as expected. That's why I was asking about temp4, since I wasn't sure at what point bB was returning the value.

     

    Going back to your original questions, I've looked at the assembly listing generated by compiling a simple DPC+ test program, and as far as I can tell the answers are as follows:

     

    Question 1 - There's a comment on the line of code where the collision is stored in temp4 that says "approx line of first pf coll," so it seems you're correct that the value in temp4 is for the y position of the pixel that collided with the playfield, but apparently it might not be the exact y position.

     

    Ah, okay. I noticed this was a little unpredictable as well, so just decided to track a hit zone the covers the full vertical range of the sprite with a top buffer of one pixel:

     

     temp2 = sprite1y + sprite1height : temp3 = sprite1y - 1
    if temp4 < temp2 && temp4 >= temp3 then sprite1pf = 1

     

    I wonder what accounts for the slight variance? Also, how do you see the assembly listing for a compiled bB program? Does DASM spit it out in a default directory?

     

    Question 2 - All collision detection on the 2600 occurs as the active portion of the screen is being drawn (i.e., during the display kernel), and normally there's no way to tell where a collision occurred, since the TIA sets the appropriate collision bit as soon as a particular type of collision is detected, and the bit remains set until you clear it. So if you forget to clear the collisions (in an assembly program) after the screen has been drawn then you can't even tell if the collision occurred on that frame or some previous frame. Fortunately for us, batari Basic clears the collision registers at the very beginning of drawscreen, so we can always be sure that any collision that was detected must have occurred on the frame that was just drawn, but we still can't tell which line the collision occurred on or whether more than one of that type of collision occurred. Since the multisprite and DPC+ kernels reuse player1 to achieve additional sprites, the ability to tell which line a player1/playfield collision occurred on was added so we can tell which of the virtual copies of player1 was involved in the collision-- at least, that's my understanding (Fred/batari could tell you for sure).

     

    Oh, okay. Again, I'm not sure I'm thinking about this the right way... but when you put it that way, the problem with my program seems to be unsolvable in bB. I can't do a manual check to see whether I should clear the player1 collision register or not, because it always begins its loop in a cleared state, starts drawing the screen, and sets the register whenever the first collision scanline is reached? I wonder if it would be possible to revise the drawscreen function to use more temp variables to store multiple collisions, with each variable assigned a certain vertical range (which sounds well above my pay grade, skill-wise).

     

    Question 3 - Only the line number for the first collision is detected this way, so if additional collisions between player1 and the playfield occur further down on the screen their positions won't be returned. I think the only way to detect the y positions of additional collisions would be to modify the kernel, and I'm not sure that's even feasible to do for a generic solution. A better suggestion would be to write your own kernel for the game, or at least edit the assembly code that's generated by compiling your batari Basic code. Assuming your test program is similar to the game you're making, with three levels and an enemy on each level, you could divide the screen into horizontal bands-- each level being a band-- and check the collisions at the end of each band, store the results, and then clear the collision registers before drawing the next band.

     

    Yeah, I was wondering too whether a solution could be generalized to store multiple lines of collision, or if the display would have to be divided into the sort of vertical bands you describe. Either way, it sounds like a new kernel would have to be written from scratch -- which is beyond my abilities, and I suppose it sort of defeats the purpose of using bB.

     

    Still, if a feasible general solution exists I wonder if this might be something batari might consider incorporating into the new version. It seems to me like that, in the absence of a pfread, it would be a very useful feature in all sorts of games that use the DPC+ kernel and virtual sprites.


  22. The temp variables are used throughout bB where needed, not just in drawscreen. For example, some of them are used in the math routines, some are used in the drawing routines, some are used when calling user-defined functions, and so on.

     

    I didn't say they were used in drawscreen, just that they were cleared after one (at least, that's what seems to be going on).

     

    That's why it's best to store or process the temp4 variable right after drawscreen, before there's any chance for it to get wiped out by some other routine.

     

    I've done that in my test program, but it doesn't change the result. I honestly don't think this is the issue here, anyway. There's not much going on in my program itself, besides a scenario that favors multiple simultaneous p1 collisions with the playfield. The problem seems to be (and, I'm not sure, which is why I'm asking) that only the collision on the highest scanline is returned in temp4, and while collisions on other scanlines are ignored. I'm just asking if anyone here can explain why this is the case, and if there's any known workaround. Sorry if I've broken some sort of protocol in asking this sort of question, I am just a novice trying to understand the result I'm seeing.


  23. Just to be clear what I mean is perform a DRAWSCREEEN then IMMEDIATELY record the collision values to real vars.

     

    That kind of why I asked question #2. It's not clear to me when the value is returned in temp4. I'm not sure what you mean by the temp variables being unreliable, though. It seems to me that while they are obliterated on a drawscreen, they work as expected as temporary variables.

     

    That's why I am interested in precisely when the Y is returned. If temp4 is reset on a drawscreen command like the other temps, then I gather that the value is being returned outside of the drawscreen (i.e., you don't have to actively test for player1/playfield collisions before retrieving the current value; you can just issue the conditional "if temp4 =.... then" whenever you want). As far as storing the values to permanent RAM, if you look at my program I think you'll see that's exactly what I'm tring to do, by trying to turn on a collision bit whenever temp4 corresponds to a given sprite's Y range.

     

    I assume by "soft collisions" you are talking about bounding boxes/hit zones, but unfortunately that isn't going to cut it for playfield collisions, which normally don't neatly correspond to rectangular hit zones like sprites do. The ability to read the state of pfpixels would sidestep the problem completely, but unfortunately from what I can tell playfield reading is not implemented yet in bB 1.1d.

×
×
  • Create New...