Jump to content
IGNORED

The Wanderers WIP


Link6415

Recommended Posts

I thought bitmap scrolling would be easier. My idea was to write a program to plot the tiles on the screen (getting data from the charset) then write an algorithm to shift them manually. They would all be black and white so I wouldn't have to worry about color memory.

Link to comment
Share on other sites

I thought bitmap scrolling would be easier. My idea was to write a program to plot the tiles on the screen (getting data from the charset) then write an algorithm to shift them manually. They would all be black and white so I wouldn't have to worry about color memory.

Nope, scrolling a bitmap is, unless you go for demo-style code which isn't guaranteed to work PAL/NTSC or at all on some machines, harder on both C64 and programmer than moving characters. 1,000 bytes of screen RAM versus 8,000 of bitmapped screen.

Link to comment
Share on other sites

Would you need it to scroll one pixel at a time as the player moves along, and are you talking about vertical scroll up/down as well as horizontal scroll left/right?

 

Besides being less data to move, another benefit with character mode is that it is easier to peek the screen and find out which character = which graphic object you've touched once you implement some form of sprite to background collission. If you work with hires, and monochrome hires as well, you would either need a logical map elsewhere in memory or compare a lot of pixels to find out what you found or hit. This is by the way one of the weaknesses with the ZX Speccy, if we allow ourselves one short intermission. It always operates in bitmapped mode and plots its characters. There is a BASIC command to determine which character is on a certain position, and that command works by comparing bitmap data on the screen with the ROM font, meaning it can't detect user definable graphics (UDG). I believe though that you can redirect the entire character generator instead of using just a few UDG's, forcing you to spend RAM on a complete font and then the BASIC command will work towards that memory space.

Link to comment
Share on other sites

Fair enough. :) Now you know the hardware scrolls one pixel at a time in either direction, no matter if you're in character or bitmap mode, and the hard work is to handle the case when data needs to be shifted to create a flow, so the same data doesn't get reset to its original position and scrolled again.

 

If you want to add colours to your game, here are a few variations of character mode you might want to consider:

 

Multicolour graphics: POKE 53270,24 : POKE 53282,AUX1 : POKE 53283,AUX2

It makes foreground colours 0-7 work like normal 8x8 cells, while 8-15 enables 4x8 cells that can have two screen wide auxillary colours (0-15) as well as the foreground (value - 8 = 0-7) and background (0-15). It can be useful for e.g. walls where you want two colours of which one is different from the general background colour.

 

Extended colour mode: POKE 53265,27 + 64 : POKE 53282,BG2 : POKE 53283,BG3 : POKE 53284,BG4

It restricts the font to 64 characters (compared to the regular 256) and uses three additional background colours (0-15). Foreground can be any of the 16 and all cells have the 8x8 resolution. For some displays this mode might be useful. You can experiment with this by trying shifted, reversed and reverse shifted characters.

 

Both those modes would be possible to combine with the scrolling bits, but for obvious (?) reasons you can't combine multicolour with extended colour, it makes the display go black.

Link to comment
Share on other sites

Would you need it to scroll one pixel at a time as the player moves along...

 

*sigh*

 

Yes.

 

I just tested the code you gave me.

 

The whole point of bitmap mode was to get a smooth scroll. Now that I see that we had a misunderstanding, I know why you were confused about why I would want to use bitmap mode in the first place.

 

I know how to move a character based map around.

 

I was trying to do a smooth scroll.

 

I knew there was a way to do it with characters, but I thought it would be more difficult. That was why I wanted to use bitmap mode.

 

 

Okay, now that we're on the same page, what is more easy, smooth scrolling a bitmap, or smooth character scrolling (as in scrolling each individual pixel.)

 

 

 

(sorry if I sound a little rude, I don't mean to be)

Edited by Link6415
Link to comment
Share on other sites

No worries, we're here to exchange expertise and I don't think you came out as rude, obnoxious or anything like that.

 

As mentioned, the hardware will scroll your display one pixel at a time no matter which graphics mode you are working with. The hard work comes when you have used up all seven steps of scrolling, and need to shift all the data in the same direction, preferrably at a point of time where the raster beam is outside the visible area so you won't notice any stuttering or flicker.

 

In character mode, you shift at most 1000 bytes - in practise you can probably shave off a little since you probably want 38 columns x 23 rows visible to make room for new graphics to be hidden in the border and appear when you scroll. If you use BASIC, you might be able to PRINT CHR$(29);CHR$(20) on each row and get any colour attributes at the same time, but a short dedicated ML routine might be faster. A custom ML routine would also support double buffered character matrix, so you can copy data from screen #1 to screen #2 at the same time you scroll screen #1, and then switch to screen #2 once the copy is done.

 

In bitmap mode, you shift at most 8000 bytes. You can shave a little here as well, under the same circumstances as above. If you would work with colour attributes on the bitmapped screen, add the same ~1000 bytes to shift those as well.

 

That is not counting the effort to plot new data onto the bitmap as you need. If you were drawing e.g. a sinus curve that would scroll along the screen, I can understand why one would want to use a bitmap instead of using a smart routine to allocate custom characters for each part of the curve.

 

So with everything sorted out, I would summarize it:

 

Character mode

+ Eight times less data to move

+ Easier to check which symbol is a certain position

- Limited to 256 different character patterns unless you would get into raster line timed changes of character generator

- You can only position elements in "whole" character positions, or define multiple characters representing a combination of objects

 

Bitmap mode

+ You can plot dots, lines, arcs, characters, symbols etc as you find required

+ With the right routine, you can plot them anywhere on screen, even across two logical character positions

- More work to plot each symbol

- Eight times more data to move when you scroll

- Could be difficult to check which graphic is at a certain position, if required

 

Good luck, and don't hesitate if you have additional questions or perhaps need a small ML helper routine (unless you write those yourself).

Edited by carlsson
Link to comment
Share on other sites

Okay, now that we're on the same page, what is more easy, smooth scrolling a bitmap, or smooth character scrolling (as in scrolling each individual pixel.)

They both use the same principles (the hardware fine scrolling applies to either mode) but the bitmap is dealing with nine or ten times the data and you won't be moving that smoothly without some fairly optimised assembly language code and two bitmaps to double buffer it; characters are always going to be easier and more memory efficient every time, although it still needs either assembly language or a good compiler to move smoothly.

Link to comment
Share on other sites

The hardware has the ability to shift the visible portion of the screen by a range of 0-7 pixels horizontally and 0-7 pixels vertically. The actual screen area remains in the same position, just the content that is shifted. Thus it really is smooth screen scrolling, not particularly char scrolling. If you only want a smaller part of the screen scrolling, you would need to get into machine code and set up the raster interrupt to trigger at a certain line, scroll/shift that area and at a later line, reset the register to the non-scrolling value. It will be a trick on your eyes that you see only part of the display scrolling.

 

(Sprites are not affected by scrolling, so they always remain in the same position)

 

You can do it the hard way too, by setting up either a block of custom graphics or go back to the bitmap mode, and then manually rotate byte by byte. It will be much slower, much more work but on computers that lack hardware support for scrolling (e.g. VIC-20 but many other) it is the way to do it if you want it to be somewhat smooth. I would doubt you want to explore this on the C64, as it has so much more convenient ways to do it.

Edited by carlsson
Link to comment
Share on other sites

*Sigh*

 

Smooth scrolling is so simple! I wasted a lot of time with the bitmap thing. Been playing around with the scrolling registers lately.

 

So, from what I can tell, I just make a copy of the screen shifted in a certain direction, scroll in that direction, the replace the current screen with the copy.

 

Okay, I think I get it now.

 

Where in memory should the 1000 byte copy go? (Is there a best place?)

 

And I must consider that the charset is at $C800.

Link to comment
Share on other sites

I would suggest that you keep your main screen matrix at $C000, your alternative screen matrix at $C400 and your character set at $C800 (2K = 256 characters). All that memory is readable and writable.

 

If you involve colours too, you probably want a buffer of the colour matrix somewhere, but since you can't change the location of the colour matrix, you would have to copy chunks of already shifted data from buffer to actual matrix. For now I fully understand if you're working with monochrome graphics and don't have to worry about this.

Link to comment
Share on other sites

Are you going to modify the character set as the game plays, or will you define/load it once and then use the symbols?

 

If you have no need to modify it as the game goes on, you probably can knock up the character set to $E000 which is writable but not as easily readable, i.e. the same location where you initially planned to put your bitmap. It would free all four kilobytes at $C000 - $CFFF for two copies of the screen matrix (which can be switched between with a single POKE), one buffer copy of the colour matrix (which would need to copied to 55296 anyway) and still have 1K free for e.g. short helper routines in ML. Your room for BASIC is uncompromised in this layout.

Link to comment
Share on other sites

You should treat each row on its own when you shift data, unless you really want characters at the extreme end on one row to appear on the other.

 

Also you can only scroll in 8 steps, so the loop to reflect 53270 shouldn't run for 16 steps.

 

I made a completely different program, that will scroll 24 lines of text. It is far beyond dog slow, much because each line is copied on its own and is double buffered. A bit of machine code would do wonders here. I'm not sure you can move 1000 characters of text within one raster frame, so you might find you want double buffering unless you want it to be jerky.

 

Oh well, I wrote a lot of text below the code segment to explain how it works, but the forum software ate all of it so I can't be bothered typing it in again.

10 poke56333,127:poke1,51:fori=0to511
12 poke57344+i,peek(53248+i):next:poke1,55:poke56333,129
14 poke56576,196:poke53272,9:poke648,192:poke53270,199:rem printchr$(147)
16 sp=0:rem here comes the scroll
18 poke53270,199-sp:s1=49152:s2=50176
20 ifpeek(53272)>9thent=s2:s2=s1:s1=t
22 fori=0to2:forx=0to38:pokes2+sp*120+i*40+x,peek(s1+sp*120+i*40+x+1)
24 nextx:pokes2+sp*120+i*40+39,int(rnd(1)*63):nexti
26 sp=sp+1:ifsp<8then18
28 rem here comes the switch
30 poke53272,1+(40-peek(53272)and24)
34 goto16
Edited by carlsson
Link to comment
Share on other sites

Variant of the same program:

 

10 poke56333,127:poke1,51:fori=0to511
12 poke57344+i,peek(53248+i):next:poke1,55:poke56333,129
14 poke56576,196:poke53272,9:poke648,192:poke53270,199:rem printchr$(147)
16 sp=0:rem here comes the scroll
18 poke53270,199-sp:s1=49152:s2=50176
20 ifpeek(53272)>9thent=s2:s2=s1:s1=t
21 poke51201,s1/256:poke51205,s2/256
22 fori=0to2:poke767,sp*3+i:sys51200:pokes2+sp*120+i*40+39,int(rnd(1)*63):next
26 sp=sp+1:ifsp<8then18
28 rem here comes the switch
30 poke53272,1+(40-peek(53272)and24)
34 goto16
Notice this one comes with a custom machine code routine, that I put at $C800 = 51200.

 

.C:c800   A9 C0      LDA #$C0
.C:c802   85 FC      STA $FC
.C:c804   A9 C4      LDA #$C4
.C:c806   85 FE      STA $FE
.C:c808   AD FF 02   LDA $02FF
.C:c80b   0A         ASL A
.C:c80c   0A         ASL A
.C:c80d   0A         ASL A
.C:c80e   8D FE 02   STA $02FE
.C:c811   0A         ASL A
.C:c812   90 08      BCC $C81C
.C:c814   E6 FC      INC $FC
.C:c816   E6 FE      INC $FE
.C:c818   E6 FC      INC $FC
.C:c81a   E6 FE      INC $FE
.C:c81c   0A         ASL A
.C:c81d   90 04      BCC $C823
.C:c81f   E6 FC      INC $FC
.C:c821   E6 FE      INC $FE
.C:c823   18         CLC
.C:c824   6D FE 02   ADC $02FE
.C:c827   90 04      BCC $C82D
.C:c829   E6 FC      INC $FC
.C:c82b   E6 FE      INC $FE
.C:c82d   85 FB      STA $FB
.C:c82f   85 FD      STA $FD
.C:c831   E6 FB      INC $FB
.C:c833   A0 00      LDY #$00
.C:c835   B1 FB      LDA ($FB),Y
.C:c837   91 FD      STA ($FD),Y
.C:c839   C8         INY
.C:c83a   C0 27      CPY #$27
.C:c83c   D0 F7      BNE $C835
.C:c83e   60         RTS
This routine will, just like the BASIC program previously, copy one row at a time. The speedup is noticable, but to avoid the flickering you really would need to wait for the raster line before swapping 53272 back and forth.
Link to comment
Share on other sites

POKE 56,144:CLR will lower BASIC RAMTOP by 4K, which means you safely can load the level to $9000 without getting it overwritten by BASIC variables. You need to issue the POKE at the beginning of the program. It would reduce your BASIC program from 38 to 34K.

 

In theory, since you're moving the VIC-II into another bank, you have 1K between 1024-2047 unused, but in case of RUN/STOP + RESTORE, you probably want to keep that kilobyte available so you don't accidentally overwrite the start of your program. While running though, you could use it for temporary data storage of the POKE kind.

Link to comment
Share on other sites

  • 3 weeks later...

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...