Jump to content

Photo

Smooth Vertical Scrolling from DATA (Want 4-way)


33 replies to this topic

#1 Gemintronic OFFLINE  

Gemintronic

    Jason S. - Lead Developer & CEO

  • 8,851 posts

Posted Fri Nov 1, 2013 3:25 PM

This my demo of smooth vertical scrolling using DATA statements.  Right now it uses a 16x16 grid where each element holds 8 horizontal pixels.

 

The trick:  adjust the playfieldpos until an entire row needs updating.  Use math (treat a single dimensional array like a 16x16 2d one) to find the x/y position of the element needed for every playfield row and update var16-47.

 

So, two issues:

 

* Some garbage pixels on the lowest visible row when scrolling.  Pretty sure it's a bB thing and not correctable.

* Collision isn't perfect when not aligned exactly with the playfield pixel.

* Must refresh EVERY playfield var instead of just immediately needed rows or columns.  If anyone can optimize it to do so please have a go!  Every time I try bB scrambles the screen.

 

The binary uses a VIC-20 style font I created.

 

RRatRace.png
Attached File  RRatRace2.bin   4KB   170 downloads
Attached File  RRatRace2.bas   9.08KB   110 downloads

 



#2 Gemintronic OFFLINE  

Gemintronic

    Jason S. - Lead Developer & CEO

  • Topic Starter
  • 8,851 posts

Posted Fri Nov 1, 2013 8:24 PM

Okay.. I'm especially numb today.  I posted this in the general 2600 programming section instead of batari BASIC where it belongs.. can a kind moderator please move this?



#3 raindog OFFLINE  

raindog

    Stargunner

  • 1,717 posts
  • Location:upstate NY, USA

Posted Sat Nov 2, 2013 2:06 PM

I'm guessing batari Basic doesn't have a 4- or 8-way scrolling kernel yet, which would mean you'd need RAM to do the horizontal part, redrawing the playfield offscreen into an array or something (I assume bB has arrays that don't need to be populated by data statements at compile time). Then you should be able to use that array instead of "world" as your playfield data in your existing code.

 

The easiest way to horizontally scroll in assembly that I know of is just ROL/ROR to rotate the playfield data, checking the carry bit and ORing it with the first/last bit in the following byte to carry it over. I don't know what the equivalent code would look like in bB, but it wouldn't surprise me if assembly were actually easier or more concise for this, at least till someone comes up with an (n > 2)-way scrolling kernel for bB.

 

If nothing else, you ought to be able to look at the released source for Princess Rescue to see how that does horizontal scrolling, and combine it with what you've done here.



#4 Gemintronic OFFLINE  

Gemintronic

    Jason S. - Lead Developer & CEO

  • Topic Starter
  • 8,851 posts

Posted Sat Nov 2, 2013 9:09 PM

I appreciate the insight raindog.

 

I think the only way to do this fast enough might involve SeaGtGruffs pfhscroll library.

 

Unfortunatly, that means that I will have to update the entire screen every playfield pixels worth of movement.

 

So I would do exactly what I'm doing now but afterwards use pfhscroll to scroll in 8 more vars worth of playfield column data.  My brain is trying to come up with a way to implement this.

 

What I wish is for something that would quickly rotate information within a byte left or right without losing information.

 

shiftleft a

 

would make a that equals "%10000100" turn into "%00001001"

 

 

shiftright b

 

would make b that equals "%00111100" turn into "%00011110"

 

%10000100



#5 raindog OFFLINE  

raindog

    Stargunner

  • 1,717 posts
  • Location:upstate NY, USA

Posted Sat Nov 2, 2013 9:22 PM

Well, that could probably be added easily to bB. This is pseudocode because I haven't written assembly in a few years:

 

shiftLeft

   rol a

   bcc shiftLeftCarry+2

shiftLeftCarry

   ora #$01

 

shiftRight

   ror a

   bcc shiftRightCarry+2

shiftRightCarry

   ora #$80

 

For all I know, there's an even simpler/faster way to do it. But I don't know that you could use these for a full-playfield horizontal scroll since you'd want to carry over to the neighboring PF byte, not the current one.



#6 Omegamatrix OFFLINE  

Omegamatrix

    Quadrunner

  • 6,134 posts
  • Location:Canada

Posted Sat Nov 2, 2013 9:43 PM

If you are shifting a ram location, then there won't be any quick way to do it. You'll probably do something like this:

 

 

;rotate left 10 cycles

lda zeropage

asl

adc #0

sta zeropage

 

 

 

;rotate right 13 cycles

lda zeropage

lsr zeropage

rol

sta zeropage

 

;rotate right 12 cycles

lax zeropage

lsr

txa

rol

sta zeropage

 

;rotate right 11/12 cycles

lda zeropage

lsr

bcc .noOr

ora #$80

.noOr:

sta zeropage

 

 

It gets worse when you are trying to index ram.



#7 bogax OFFLINE  

bogax

    Dragonstomper

  • 718 posts

Posted Sun Nov 3, 2013 11:57 AM

I appreciate the insight raindog.

 

I think the only way to do this fast enough might involve SeaGtGruffs pfhscroll library.

 

Unfortunatly, that means that I will have to update the entire screen every playfield pixels worth of movement.

 

So I would do exactly what I'm doing now but afterwards use pfhscroll to scroll in 8 more vars worth of playfield column data.  My brain is trying to come up with a way to implement this.

 

What I wish is for something that would quickly rotate information within a byte left or right without losing information.

 

shiftleft a

 

would make a that equals "%10000100" turn into "%00001001"

 

 

shiftright b

 

would make b that equals "%00111100" turn into "%00011110"

 

%10000100

 

I'm not sure exactly what you want.

 

What's wrong with SeaGtGruff's scrolling?

 

I don't think there's going to be any way to scroll horizontally

that doesn't involve doing the Whole screen.

 

The bytes in the screen area are alternately reversed so

I think your best bet is to scroll a entire line at a time.

 

In bB I think the best thing to do would be to scroll horizontally

and then poke in the new column from ROM.

 

If you're trying to do vertical scrolling from ROM

it may be that shifting one line's worth of data into

 a buffer then vertically scrolling that into place

would be about as fast and easy as anything.

 

I haven't tryed it but I don't think it would be any faster

to shift individual bytes then combine them to make a line.

(possibly huge look up tables could be faster)

 

I'd guess it would be possible to combine vertical and

horizontal in to one routine.

I'd try scrolling the new vertical line in to a buffer then

scroll vertically while scrolling each line horizontally as

I went.

You'd want dedicated routines for each direction.

Whether you picked up the new column as you went

or filled it in after might depend on whether you were

doing that in bB or in asm.

 

I know the subject of reversing bytes has come up before.

you can do it a bit at a time or with partial (nybble) look up

 tables or with full (byte) look up tables.

 

My choice (for bB) would be by nybbles.

function rev()
temp2 = temp1 & $0F
temp1 = temp1 / 16
temp1 = revhi[temp2] | revlo[temp1]
return

data revhi
$00, $80, $40, $C0, $20, $A0, $60, $E0
$10, $90, $50, $D0, $30, $B0, $70, $F0
end

data revlo
$00, $08, $04, $0C, $02, $0A, $06, $0E
$01, $09, $05, $0D, $03, $0B, $07, $0F
end

Here's code that scrolls (rotates actually) a single line

COLUBK = $35
COLUPF = $55



playfield:
................................
.X.X.X..........................
................................
................................
................................
................................
................................
................................
................................
................................
end


Main

drawscreen

a = a + 1
if a & $0F then Main

if joy0right then gosub scroll_right
if joy0left then gosub scroll_left

goto Main

scroll_right
asm
lda var7
rol
ror var4
rol var5
ror var6
rol var7
end
return

scroll_left
asm
lda var4
rol
ror var7
rol var6
ror var5
rol var4
end
return

edit here's code for the whole screen

 

COLUBK = $35
COLUPF = $55



playfield:
.X.X.X..........................
.X.X.X..........................
.X.X.X..........................
.X.X.X..........................
.X.X.X..........................
.X.X.X..........................
.X.X.X..........................
.X.X.X..........................
.X.X.X..........................
.X.X.X..........................
.X.X.X..........................
.X.X.X..........................
end


Main

drawscreen

rem a = a + 1
rem if a & $0F then Main

if joy0right then gosub scroll_right
if joy0left then gosub scroll_left

goto Main

scroll_right
asm
lda var3
rol
ror var0
rol var1
ror var2
rol var3
lda var7
rol
ror var4
rol var5
ror var6
rol var7
lda var11
rol
ror var8
rol var9
ror var10
rol var11
lda var15
rol
ror var12
rol var13
ror var14
rol var15

lda var19
rol
ror var16
rol var17
ror var18
rol var19

lda var23
rol
ror var20
rol var21
ror var22
rol var23

lda var27
rol
ror var24
rol var25
ror var26
rol var27

lda var31
rol
ror var28
rol var29
ror var30
rol var31

lda var35
rol
ror var32
rol var33
ror var34
rol var35

lda var39
rol
ror var36
rol var37
ror var38
rol var39

lda var43
rol
ror var40
rol var41
ror var42
rol var43

lda var47
rol
ror var44
rol var45
ror var46
rol var47
end
return

scroll_left
asm
lda var0
rol
ror var3
rol var2
ror var1
rol var0

lda var4
rol
ror var7
rol var6
ror var5
rol var4

lda var8
rol
ror var11
rol var10
ror var9
rol var8

lda var12
rol
ror var15
rol var14
ror var13
rol var12

lda var16
rol
ror var19
rol var18
ror var17
rol var16

lda var20
rol
ror var23
rol var22
ror var21
rol var20

lda var24
rol
ror var27
rol var26
ror var25
rol var24

lda var28
rol
ror var31
rol var30
ror var29
rol var28

lda var32
rol
ror var35
rol var34
ror var33
rol var32

lda var36
rol
ror var39
rol var38
ror var37
rol var36

lda var40
rol
ror var43
rol var42
ror var41
rol var40

lda var44
rol
ror var47
rol var46
ror var45
rol var44
end
return

Edited by bogax, Sun Nov 3, 2013 12:22 PM.


#8 Gemintronic OFFLINE  

Gemintronic

    Jason S. - Lead Developer & CEO

  • Topic Starter
  • 8,851 posts

Posted Sun Nov 3, 2013 1:08 PM

I updated the first post with my success in getting westward scrolling going.

 

Two big limitations:

* The left side doesn't get a new set of data until 8 pixels have gone past.  Pretty rough clipping there.

* The playfield data must be symmetrical since the center columns get reversed.

 

So, am I reading that the "best" way to reverse all the bits in a byte is to make a huge lookup table?

 

..and by reverse I mean %10100010 becomes %01000101



#9 Gemintronic OFFLINE  

Gemintronic

    Jason S. - Lead Developer & CEO

  • Topic Starter
  • 8,851 posts

Posted Tue Nov 5, 2013 1:28 AM

A further update: rough horizontal scrolling at top.

 

Up to 7 or 8 playfield pixels wide gap appears when scrolling.  A proper scroller would fill in the new column of playfield pixels every time.

 

Also, for some weird reason the last row of playfield pixels now wants to freakin offset itself.  sigh.

 

Reversing bits in a byte is still a mystery so again: the playfield data must be symmetrical until I solve this.



#10 Gemintronic OFFLINE  

Gemintronic

    Jason S. - Lead Developer & CEO

  • Topic Starter
  • 8,851 posts

Posted Sat Nov 9, 2013 1:22 PM

New version at top!

 

Playfield data no longer has to be symmetrical.  The horizontal scrolling is still rough because no new map data is being pulled until every 8 pixels.

 

Using phfscroll feels like the right solution to scroll in the new world data but how to implement it is baffling me.

 

Unless we're going over cycle this means 4 way scrolling is working: just not clipped very well at the edges.



#11 bogax OFFLINE  

bogax

    Dragonstomper

  • 718 posts

Posted Sat Nov 9, 2013 3:29 PM

It's a pity the functions in bB are so damn primitive


Here's a function to supply a byte from your table
indexed by the function parameter so instead of

temp4 = world[chunkb]
var45 = rev(temp4)

you'd do

var45 = wrev(chunkb)

function wrev
asm
tax
lda world,x
and #$0F
tay
lda world,x
lsr
lsr
lsr
lsr
tax
lda revhi,y
ora revlo,x
rts
end

data revhi
$00, $80, $40, $C0, $20, $A0, $60, $E0
$10, $90, $50, $D0, $30, $B0, $70, $F0
end

data revlo
$00, $08, $04, $0C, $02, $0A, $06, $0E
$01, $09, $05, $0D, $03, $0B, $07, $0F
end

Of course, it's dedicated to the world table,
so you can only use it with the world table.

If you change the name of the table you'd have
to change it in the asm of the function.

It's untested.


There's nothing wrong with pfhscroll
but I think I'd use something less general purpose.


Damn, this editor sucks.

Edited by bogax, Sat Nov 9, 2013 3:42 PM.


#12 bogax OFFLINE  

bogax

    Dragonstomper

  • 718 posts

Posted Sat Nov 9, 2013 4:32 PM


 

Using phfscroll feels like the right solution to scroll in the new world data but how to implement it is baffling me.

 

 

scroll vertically

 

copy table data to the "blank" line thats left

 

scroll the line with the new table data into postion

relative to the screen using pfhscroll

 

then use pfhscroll to scroll horizontally

 

each time you use pfhscroll you'll have to find

the correct data in the table to scroll in

(except in the case of the table and screen

being alligned while vertical scrolling)



#13 Gemintronic OFFLINE  

Gemintronic

    Jason S. - Lead Developer & CEO

  • Topic Starter
  • 8,851 posts

Posted Sat Nov 9, 2013 5:13 PM

bah.  I tried using pfhscroll to scroll just one pixel at a time.  Trouble is, I don't seem to be extracting the bits properly.  Somehow pfhscroll just uses the first bit of the data element.  My efforts to rotate a byte left or right has failed so far.

 

I think my best chance is to use my hadjust variable to determine if pfhscroll should move left or right.  Then I'll have to read in 8 more data elements from the respective side and do 8 more pfhscroll commands.

 

MANY THANKS to bogax again for the wrev function.  I've managed to streamline the code a bit.



#14 Gemintronic OFFLINE  

Gemintronic

    Jason S. - Lead Developer & CEO

  • Topic Starter
  • 8,851 posts

Posted Sun Nov 10, 2013 1:01 AM

Okay folks!  We've done it!  First post as usual.

 

Four way scrolling has been achieved.  The only problem is JUST scrolling around is almost over cycle.  I had to remove the last playfield row otherwise the calculations would cause things to go over cycle.

 

I really wish this could be done tighter but I don't see how.



#15 bogax OFFLINE  

bogax

    Dragonstomper

  • 718 posts

Posted Sun Nov 10, 2013 5:20 AM

Okay folks!  We've done it!  First post as usual.

 

Four way scrolling has been achieved.  The only problem is JUST scrolling around is almost over cycle.  I had to remove the last playfield row otherwise the calculations would cause things to go over cycle.

 

I really wish this could be done tighter but I don't see how.

You don't have to keep copying data
from the table to the screen and
fixing it (reverseing it, scrolling
it in to position)

Most of the data for the playfield
as it will be after scrolling is already
in the playfield variables in pretty much
the right place.

Assuming you're scrolling one pixel
at a time, there's one line you'll
have to fix if you're scrolling vertically
and one column of pixels you'll have
scroll in if you're scrolling horizontally

If you're scrolling both vertically and
horizontally there might be some advantage
to combining them in one operation but I'd
start with doing them seperately probably
scrolling vertically first then horizontally

It seems reasonable to let hadjust range
up to 7 to begin but eventually it should
never have to be more than +-4.

You'd need vertical scrolling routines that
just copy playfield variables to other playfield
variables.
Be they unrolled or in for loops they should be
faster and have more consistant timing than
scrolling lines from the table into place.

Once you've scrolled vertically you should need
just one line from the table to fill/fix
for the line in the new, scrolled playfield
that wasn't in the old playfield before you
scrolled vertically
(assuming you're scrolling no more than one
pixel at a time)

Then you can do you're horizontal scrolling
and hadjust should never be more than +-1
 


Edited by bogax, Sun Nov 10, 2013 5:28 AM.


#16 Gemintronic OFFLINE  

Gemintronic

    Jason S. - Lead Developer & CEO

  • Topic Starter
  • 8,851 posts

Posted Wed Nov 13, 2013 12:01 PM

I'm pretty sure this is as good as it gets for me.  New code and binary at top.

 

I reverted the redraw code to an earlier build that did not go over cycle when var44 - var47 (bottom row) was used.  Now both the top and bottom clip SMOOOTHLY.

 

Despite some tricks collision is still a bear.  I've mitigated the issues but things a little sticky when not well aligned with the playfield.  You'll notice the maze has 2 playfield pixel tall horizontal passages.  Also, 5 playfield pixel wide vertical passages.  batari didn't even try moving in fractional playfield pixels in his Rally-B demo.



#17 bogax OFFLINE  

bogax

    Dragonstomper

  • 718 posts

Posted Sun Nov 17, 2013 3:50 PM

Darn you theloon, darn you all to heck!
I set this scrolling stuff aside untill
I could get a proper playfield editor going.
How dare you tempt me :P

But since I had your world data ..

This (is mostly) what I was trying to
discribe.
I think the only major difference is that
this picks up the fill in column and shifts
it in when scrolling horizontally instead of
scrolling then filling it in.

I just sort of banged this out so I don't
guarantee there's no bugs, but it seems to work.

Except for the shifting I think it's all in bB
it could undoubtedly be improved. I wasn't trying
to make it small or fast, I was trying to make it
straight forward and understandable.

Of course it's set up for 16 byte by 16 byte
world data

4way.bas
 



#18 Random Terrain ONLINE  

Random Terrain

    Visual batari Basic User

  • 28,245 posts
  • Controlled Randomness
    Replay Value
    Nonlinear
  • Location:North Carolina (USA)

Posted Mon Mar 2, 2015 11:14 PM

Did you update your code with what bogax posted or improve it in some other way?



#19 Gemintronic OFFLINE  

Gemintronic

    Jason S. - Lead Developer & CEO

  • Topic Starter
  • 8,851 posts

Posted Wed May 27, 2015 1:56 PM

Did you update your code with what bogax posted or improve it in some other way?

 

No.  Bogax made his own improvements on an earlier build.  The top post should have the most up-to-date code.  It scrolls pretty smoothly now.



#20 Lewis2907 OFFLINE  

Lewis2907

    Chopper Commander

  • 138 posts
  • Location:Senatobia, MS

Posted Mon Oct 23, 2017 8:54 PM

This maybe over my head, but how hard is it to go from "16 byte by 16 byte world data" to 32 byte, 32 byte. Just wondering what part of the code you have to adjust, thanks.



#21 Gemintronic OFFLINE  

Gemintronic

    Jason S. - Lead Developer & CEO

  • Topic Starter
  • 8,851 posts

Posted Tue Oct 24, 2017 9:01 AM

This maybe over my head, but how hard is it to go from "16 byte by 16 byte world data" to 32 byte, 32 byte. Just wondering what part of the code you have to adjust, thanks.

 

I had to heavily lean on bogax for the scrolling code.  The level data is specifically laid out so that editing playfield pixels from the source code was dead simple.  Basically, every 1 or 0 is one playfield pixel.  Trying to change the way the DATA statements are put together would mess with that.



#22 Lewis2907 OFFLINE  

Lewis2907

    Chopper Commander

  • 138 posts
  • Location:Senatobia, MS

Posted Tue Oct 24, 2017 9:09 AM

Gemintronic,

 

I found that out and it's nice. I am playing with it to convert the "Save Earth" over and some other open world games I have in mind. I am able to do Playfield detection in certain "Worlds" based upon if I need to create a border or something. Plus this code here saves a lot space vice the normal Playfield that I learned when I first came over to using Bb. I will play with on how to make 8 byte, 32 byte etc. If not I can work with the 16 byte. Plus the code works fine on AFP where I have decided to gear what I make work on. Bogax has helped me in the past especially with "Exit Flags" for Pac Man Eat n Run. Hopefully its a few simple tweaks here and there to make the Data World s smaller, larger or longer. Thanks again for sharing the code. It has helped me learn. I will need to learn assembly at some point to make it easier on me, thanks. 



#23 Gemintronic OFFLINE  

Gemintronic

    Jason S. - Lead Developer & CEO

  • Topic Starter
  • 8,851 posts

Posted Tue Oct 24, 2017 10:01 AM

The best answer is to move to assembly.  The next best answer is to use Mr SQLs vwBASIC as it has built in support for large playfields.

http://atariage.com/...239347-vwbasic/

 

My method here uses a LOT of CPU time.



#24 bogax OFFLINE  

bogax

    Dragonstomper

  • 718 posts

Posted Thu Oct 26, 2017 9:41 PM

speaking for my code

while you could undoubtedly speed it up in asm I don't think it would be that dramatic

the first thing I'd do is unroll the vertical scrolling and you could do that in bB

 

as to a 32 x 32 byte world you'ld need to change some constants.

simplest would probably be to break out the world rows in to individual

data statements you could then look up the data statement in a table

and use a few bytes of asm to do the actual look up (because 32 x 32 is too big for a data statement)

you might be able to jimmy it into sdata but I think that would bring some cruft and it really only needs

a few bytes of asm

 

some thing like

 

 
 data wrow0
 some, stuff, other, stuff, more, stuff, etc
end
 
 data wrow1
 some, stuff, other, stuff, more, stuff, etc
end
 
 data wrow2
 some, stuff, other, stuff, more, stuff, etc
end
 
etc
 
data wrow_addresslo
<wrow0, <wrow1, <wrow2, <wrow3
end
 
data wrowaddresshi
>wrow0, >wrow1, >wrow2, >wrow3
end
 
 
 
 temp2 = wrow_addresslo[wrow_number]
 temp3 = wrow_addresshi[wrow_number]
 
 temp1 = index
 
; fetches your world data to temp1
asm
ldy temp1
lda (temp2),y
sta temp1
end
 


#25 Sprybug OFFLINE  

Sprybug

    Dragonstomper

  • 554 posts

Posted Fri Nov 3, 2017 7:52 PM

If you want to see how I did horizontal scrolling in Princess Rescue, just go to Random Terrain's Batari site, and he has my source code for it there, along with added documentation.  You can find how I did my scrolling in there with the ScrollLeft and ScrollRight routines.  I did use pfhscroll, but with some added code.  When new data needed to show up, it would look at the new data I had in the level data table, using a pointer, to pick up the 2 new bytes, and then it would compare bit by bit with what the var screen variables had on the edge of the screen.  If it didn't match up, it would flip the bit, saving time so it didn't redraw every bit on the edge of the screen.


Edited by Sprybug, Fri Nov 3, 2017 7:53 PM.





0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users