Jump to content
IGNORED

Horizontal Scrolling Help


Master_Programmer

Recommended Posts

If you're okay with two horizontal rows you could scroll the screen then do a playfield: data statement that DOES NOT cover the entire screen. So, scroll, playfield data, redraw.

 

Another way would be to have your level data in an array and just pfpixel the view within that data array. I was working on the maths to treat an 8-bit one dimensional array as a 2d binary array

http://www.atariage.com/forums/topic/200939-accessing-data-as-binary-array/

 

If we could get it working we'd have cheap collision maps and level maps for multi-screen big levels!

Link to comment
Share on other sites

Let's say I have one row of clouds, made up of the playfield's top line.

 

i scroll it.

 

then I have a second line of clouds, but it scrolls twice for every scroll of the first line.

 

and so on, and so forth.

It sounds like your best option is to write (or ask someone else to write) a custom horizontal scrolling routine. It could be a general function that would scroll a range of lines by a specified amount, with an option to set the new pfpixel on, off, or get it from the pfpixel that's being scrolled off the other side. For example, since "pfscroll" is the name of batari Basic's builtin command, so let's call it "pfhscroll." Then the function call might be in the form of "pfhscroll(firstline,lastline,amount,newpixel)," where the arguments are numeric values, such as 0 for no scroll, 1 for scroll right 1 pfpixel, 255 (i.e., -1) for scroll left 1 pfpixel, 0 for newpixel off, 1 for newpixel on, or 255 for get newpixel from the pfpixel that's being scrolled off the screen.

Link to comment
Share on other sites

That's not even close to what I meant.

 

Let's say I have one row of clouds, made up of the playfield's top line.

 

i scroll it.

 

then I have a second line of clouds, but it scrolls twice for every scroll of the first line.

 

and so on, and so forth.

 

What me and SeaGtGruff mean is that you need to make your own scrolling routine. My idea would be to do it using a DATA array. If you just want to move pixels around then I guess you could pfread the pixel you want to move then pfpixel it left or right. I don't know if this would be faster or slower than reading the playfield data from an array or not. I say test both methods.

Edited by theloon
Link to comment
Share on other sites

I took a stab at creating a general "pfhscroll" user function. This is version 1.0, and for the time being it works exclusively with the standard kernel, no Superchip playfield. I'm sure the code can be improved-- I was more interested in getting it to work than optimizing it, and I had quite a time debugging it. I'm not too sure about the option to scroll with or without wraparound-- my idea was to let you scroll new values into a line, instead of being stuck scrolling the same line over and over, but I need to rethink the way it's implemented. The code for the function is written in assembly, but hopefully it isn't too difficult to follow. There's a bunch of remarks at the beginning of the function code that explains the arguments. The program also demonstrates the function by scrolling three different areas of the playfield. The top row of clouds scrolls 1 pfpixel to the left. The middle row of clouds scrolls 2 pfpixels to the right. And the bottom row of clouds scrolls 3 pixels to the left. Whee!

pfhscroll_v10_demo1.zip

  • Like 1
Link to comment
Share on other sites

For version 2.0 (which I'll hopefully post tonight when I'm done), I'm planning to change the arguments as follows:

 

start -- [required] Same as before, the row number to start with.

rows -- [required] The number of rows to scroll (rather than having a stop row number).

amount -- [required] Same as before, the number of pfpixels to scroll left (negative values) or right (positive values), up to 8 pfpixels.

wraparound -- [optional] Flag to indicate whether to use wraparound (0) or scroll in new graphics (1); the default (if the argument is omitted) is to use wraparound.

graphics -- [optional] The new graphics data (1-byte binary) to scroll into the row.

 

So everything will basically be the same except for replacing the stop row number with the number of rows, and adding a dedicated wraparound flag instead of trying to use the new graphics data byte to double as the wraparound flag.

 

As for the routine itself, I plan to make it Superchip compatible. And I'm embarrased to admit this, but I haven't even dabbled with the DPC+ kernel yet to where I even know how the playfield works. If it isn't too hard for me to figure out the DPC+ playfield setup, I'll try to add DPC+ compatibility as well. Also, I don't know if it would be worth it to add support for the multi-sprite kernel if the playfield isn't full-width, but I'll check into that as well.

 

Finally, I'll be putting the routine into its own .asm include file, rather than having it embedded within a demo program as version 1.0 was.

Link to comment
Share on other sites

@SeaGtGruff

 

So, if you choose to scroll more than one row it duplicates the 8-bit map data on all rows? So if you specified 2 rows and gave it a value of %10000000 then the solid block would be made on both rows?

 

If you wanted to use this to scroll in map data one pixel at a time how does that work? If you move 1 pixel with %1000000 then try it again you just end up repeating that first %1, right? Would you have to somehow rotate/shift that 8-bit value so it uses the first digit then second then third, etc..

Edited by theloon
Link to comment
Share on other sites

I was wrong, the wraparound flag will need to be required, because if it isn't set then its value will be unpredictable.

 

I've successfully moved version 1.0 into an assembly include file, optimized the code a bit, and updated it to use the new parameters, then revised the first demo to use the include file using the "inline pfhscroll.asm" instruction after the main program loop. I still need to add support for the Superchip playfield, DPC+ playfield (once I figure out how it's set up), and possibly the multi-sprite Superchip playfield. (If I remember correctly, the non-Superchip multi-sprite playfield is in ROM, so it can't scroll horizontally.)

 

@SeaGtGruff

 

So, if you choose to scroll more than one row it duplicates the 8-bit map data on all rows? So if you specified 2 rows and gave it a value of %10000000 then the solid block would be made on both rows?

 

If you wanted to use this to scroll in map data one pixel at a time how does that work? If you move 1 pixel with %1000000 then try it again you just end up repeating that first %1, right? Would you have to somehow rotate/shift that 8-bit value so it uses the first digit then second then third, etc..

Hmm, I don't think version 1.0 will handle scrolling in the new graphics data correctly, so I'll need to fix that in the version 2.0 include file. The way it was intended to work is that the new graphics data will be used on all rows in the specified range, but the scrolling routine shifts the bits out one by one as each row is scrolled, and it (currently) doesn't preserve and restore the graphics data so it can be reused on the next row. That should be easy enough to fix.

 

If you want different graphics data scrolled in on each row, then you'll need to call the function for each row and specify the desired graphics data. This would also be a way to get around the bug in version 1.0 that wipes out the specified graphics data each time a row is scrolled-- although that will be fixed in version 2.0.

 

As for the graphics data bits, if you're scrolling 3 pfpixels and want to scroll in 3 new graphics bits, then you'll need to specify the 3 bits when you call the function. Rather than right-justify everything, I decided it makes more sense to justify the data according to the direction you're scrolling in, left or right. That is, if you're scrolling right 3 bits then the new bits should be specified in bits 0, 1, and 2 of the graphics data argument, and they'll be shifted into the playfield in that order-- bit 0 first, then bit 1, then bit 2. But if you're scrolling left 3 bits then the new bits should be specified in bits 7, 6, and 5 of the graphics data argument, and they'll be shifted into the playfield in that order-- bit 7 first, then bit 6, then bit 5.

 

After I get version 2.0 finished-- or as much of it as I can complete tonight (the DPC+ and multi-sprite playfields might need to wait for version 3.0)-- I'm going to write a demo of scrolling in new graphics data. My current plan is to define a wide playfield (say, 64 pfpixels across) as ROM data, then scroll the data in a pixel at a time, so hopefully the demo for version 2 will show you at least one way you could do it.

 

Keep in mind, I may run into issues as I'm adding compatibility for the other types of playfields (Superchip, DPC+, etc.). Last night I hammered out the initial code pretty quickly, but then it took me literally several hours to debug it! (I guess I'm not the whiz programmer I thought I was. ;))

 

By the way, I should mention that the function doesn't check the parameters to make sure the values in each argument are "legal"-- or even that there's enough arguments. So when calling the function you need to make sure you're passing it good values.

Link to comment
Share on other sites

Okay, version 2.0 did not go so well. Well, the include file and the first demo (scrolling with wraparound) went great! But the second demo (scrolling in new graphics data) went horribly, and took several hours to fix. It wasn't my fault, I swear! There were three issues I ran into:

 

(1) You cannot use a variable in a function call, so something like "a = pfhscroll(row, 1, 1, 1, new_data)" will not work. I had to get around that by putting in a bunch of function calls with fixed row numbers, and leaving out the fifth argument. It would have been nice to be able to use a variable for the row number, but leaving out the fifth argument wasn't so bad, because all you need to do is set temp5 before calling the function.

 

(2) You cannot use a variable in a bit function, so something like "new_data{7} = byte{bit_number}" will not work. I had to get around that by using a bunch of "if" statements, which works but is less elegant.

 

(3) But the real killer is that, if you use an array statement-- say, "byte = my_pf_data[offset]"-- then for some reason the batari Basic compiler tries to interpret the function call as a complex statement, resulting in a syntax error. I had to get around that by using inline assembly code to do the same thing.

 

So I was finally able to get the second demo working.

 

Version 2.0 is in an assembly include file named pfhscroll.asm, and I've commented the code to document the arguments and to try to explain the assembly code a little bit. This version works with a Superchip playfield, but demo 2 ate my lunch (as my boss would say), so I haven't attempted to tackle a DPC+ playfield yet, and I'm still uncertain if horizontal scrolling for a Superchip multi-sprite kernel playfield is worth it.

 

Demo 1 scrolls a Superchip playfield using wraparound. It uses the same "clouds" screen that the version 1.0 demo did, but I increased the number of playfield rows to 32 (or 31 visible rows, since row 32 is hidden by the score). It should be noted that scrolling a Superchip playfield takes a lot more cycles than scrolling a RIOT playfield, since the Superchip RAM addresses can't be rotated directly-- you must load the RAM byte into the accumulator from its read address, rotate the accumulator, and then store the new value back to RAM using its write address. For demo 1 I had to add an extra "drawscreen" in about the middle of the function calls to avoid screen flickering in Stella (or screen roll on a TV). And that's without any "game housekeeping chores"-- so in an actual game, the amount of Superchip playfield scrolling you can fit onto a single frame could be pretty small, requiring you to divide the scrolling up across multiple frames as I did in demo 1.

 

Demo 2 (AKA "The demon straw from the 13th level of Hell that broke batari Basic's camel's back") scrolls a Superchip playfield, but moves new graphics data into the playfield. It uses a 64-bit-wide "virtual playfield" that is defined in a ROM data table-- 8 bytes wide and 15 lines tall. The same data is scrolled into the top and bottom halves of the screen, but from opposite sides and in opposite directions-- the top half of the screen scrolls through the data from right to left, and the bottom half scrolls through the same data from left to right. I had to insert three extra "drawscreen" statements to divide up the scrolling between four frames.

 

Edit: I just realized that the remarks in demo 2 refer to it as demo 1-- no biggie, but if you save it on your computer you might want to change the remark to say demo 2.

pfhscroll.zip

Edited by SeaGtGruff
Link to comment
Share on other sites

Slight improvement to the include file-- I realized that by moving some code (thereby saving a few bytes and cycles) I didn't need to use old_pixel, so I redefined new_pixel as temp1, leaving temp6 untouched.

 

I tested the change by recompiling the demos, but the attachment contains only the updated include file (version 2.1).

pfhscroll_v21.zip

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

Wow.. this library could be used for more than sizzlean slim slices of playfield.. You could probably use this for a full screen 4 way scrolling platform game!!!!!

I don't think the current pfhscroll routine is suitable for that, since it's specifically designed to allow scrolling of selected rows, a choice of how far to scroll, a choice of using wraparound or no wraparound, and does only horizontal scrolling. Therefore it contains extra logic that wouldn't be needed for scrolling the entire playfield.

 

I haven't done much with batari Basic's pfscroll routine, but in theory it should be able to handle 4-way scrolling of the entire screen within a huge playfield map. It's true that its horizontal and vertical scrolling uses wraparound, but for vertical scrolling you just need to set the hidden playfield row to the new data, and for horizontal scrolling you can use pfpixel to set the bits in the new column after scrolling with wraparound. I'm not saying that's the fastest/best way to do it, just that it should be possible.

 

One advantage of using pfhscroll is that you can divide the scrolling across multiple frames if trying to scroll the entire playfield at once takes up too many cycles-- but you have to be careful how you do that or it can cause the screen to "ripple" or "tear" as it scrolls due to different rows being scrolled on different frames. You might be able to minimize this effect by carefully selecting the rows where you split the scrolling, and also by scrolling only after a certain number of frames. For example, once I got the demo with the scrolling playfield text working, I had to add extra drawscreens so the screen didn't go over 262 lines, and at first the descender of the lowercase "p" in "example" looked like it was trailing behind a bit, because I'd inserted an extra drawscreen between the scrolling of the top part and the scrolling of the descender-- so I moved the extra drawscreen to put it after the descender row to correct the trailing effect.

 

I was thinking it might be nice to have a pfvscroll routine as well, to allow vertical scrolling of selected columns with a choice of wraparound or no wraparound, but I'm not ready to tackle that yet, so I'm placing it on the back burner to simmer in my head for a while.

 

Likewise, a 4-way scrolling routine that's dedicated to scrolling around within a huge playfield map would also be nice-- maybe it could be called pf4scroll.

 

Getting back to pfhscroll, I'm wondering about any issues there might be with scrolling a DPC+ playfield. For example, it's my understanding that the DPC+ kernel allows you to set different vertical resolutions for the different playfield registers. Keep in mind, I haven't dabbled with the DPC+ kernel very much at all, so forgive me if I'm wrong about that, but I thought there was a demo program that did that (although I can't find it now). And I'm not even certain how the playfield data is organized in memory for the DPC+ kernel. In any case, horizontal scrolling of a DPC+ playfield would be feasible only if the playfield display bytes are stored in RAM, and only if all of the columns have the same vertical resolution.

Link to comment
Share on other sites

I need to go back and correct some things I said.

 

(1) You cannot use a variable in a function call,

This is not true, you certainly can use a variable as an argument in a function call. I honestly don't know why I was having problems with this, but I think it was being caused by something else.

 

(2) You cannot use a variable in a bit function,

This is true, and has been true for a long time, so I'm not "correcting" that remark. It does seem like it should be easy to add support for variables in bit operations, but there may be a good reason why this hasn't been done yet. In any case, bogax posted some great tips about accessing selected bits in the "Accessing DATA as binary array" thread, and it should also be possible to write a user function to read or write a selected bit using a variable argument.

 

(3) But the real killer is that, if you use an array statement-- say, "byte = my_pf_data[offset]"-- then for some reason the batari Basic compiler tries to interpret the function call as a complex statement, resulting in a syntax error.

This is not true-- I tried a simple test and was able to use an array access followed by a function call. So again, I think there must have been some other issue at work that was causing the compiler to treat my function call as a complex statement, but I haven't figured out what the real problem was.

 

I could probably go back and rewrite my demo 2 program to be more concise and elegant, but I don't particularly want to do that-- it is what it is! :)

Link to comment
Share on other sites

You should call a moderator SeaGtGruff :) Sounds like your getting into a heated reply war with yourself :P

 

I already thanked you in another thread but thanks again for this sudden, excellent scrolling routine. I think it could not only solve the OPs raster effect kinda use but also horizontal scrolling games in general.

Edited by theloon
  • 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...