Jump to content





Possible Wild Western Port using SC

Posted by , 03 January 2006 · 858 views

Wild Western 2600 Game Development SuperCharger
MANUEL got me thinking about a Wild Western port.

At first I thought it was too simple of a game to need the Supercharger, but I'm reconsidering.

Using strips of RAM to display sprites/particles would allow this kind of kernel:
  lda RAM,Y
  sta GRP0
  lda RAM,Y
  sta GRP1
  lda RAM,Y
  sta COLUP0
  asl
  sta ENAM0
  lda RAM,Y
  sta COLUP1
  asl
  sta ENAM1
  lda RAM,Y
  sta ENABL   ;+45
Assuming that Y ranges from 0 to 160, that would require about 800 bytes of RAM. Using 45 cycles leaves about 25 for other displayed objects.

Those other displayed objects are:
1. The train in the center, which AFAIK doesn't really move
2. The train tracks in the center, which do scroll vertically.
3. Obstacles (cactus, rocks, etc.) which also scroll vertically.

If I draw those with the PF, making them symmetrical with a reflected PF, then I can do this...
  lda RAM,Y
  sta PF0
  lda RAM,Y
  sta PF1
  lda RAM,Y
  sta PF2   ;+21
Which takes up almost an entire scanline. But I'd probably update the particles every other line (or even every third/fourth), leaving plenty of time to reposition the sprites.

Problems:
1. Drawing trains and obstacles with the playfield. Might get ugly.
2. Controls? The arcade uses a joystick, an 8-position rotary controller and two buttons.

Possibilities:
A) Use two controllers: Joystick in port 1, DC in port 2. Might work if you could operate the DC and its button with one hand. :| This might make a good 2-player variation, though.
B) Shoot in direction you are moving or last moved. Not sure how to have him jump on the train, though.

Don't really like A or B. Anybody else have any brilliant ideas? :D




Hi there!

I may post more regarding this subject tomorrow, but before going to bed I thought to show you something. Just go there:
http://www.atarihq.c...eum/2678/games/
- and click the Wild Western link :)

Greetings,
Manuel
  • Report

Hi there!

I may post more regarding this subject tomorrow, but before going to bed I thought to show you something. Just go there:
http://www.atarihq.c...eum/2678/games/
- and click the Wild Western link :D

Greetings,
Manuel

Thanks for the link. Looks like the same method for drawing the tracks and obstacles that I thought of, plus what looks like a real nice overlay for your TV screen for the train. :)
  • Report
Hi there!

Thanks for the link.  Looks like the same method for drawing the tracks and obstacles that I thought of, plus what looks like a real nice overlay for your TV screen for the train. :)


Hehe... well unfortunately that's exactly the main problem though, the train, no?

The best solution I could think of so far would be using one sprite for the train and multiplex the other for all riders.

Greetings,
Manuel
  • Report
While the kernel might look doable with SC-RAM, it is IMO most likely impossible to add any scrolling to it now.

I am currently working on a scrolling game which "only" uses ~200 bytes of SC-RAM for the playfield. And that's already almost too much for scrolling, even though I use double buffering (scrolling every 2nd frame now). Especially horizontally scrolling is a real CPU time killer.

For vertical scrolling (like in Wild Western), you should use an index table for Y. So you only have to adjust the index table, and not the whole SC-RAM. But that requires a few extra cycles in your kernel.
  • Report

While the kernel might look doable with SC-RAM, it is IMO most likely impossible to add any scrolling to it now.

I am currently working on a scrolling game which "only" uses ~200 bytes of SC-RAM for the playfield. And that's already almost too much for scrolling, even though I use double buffering (scrolling every 2nd frame now). Especially horizontally scrolling is a real CPU time killer.

For vertical scrolling (like in Wild Western), you should use an index table for Y. So you only have to adjust the index table, and not the whole SC-RAM. But that requires a few extra cycles in your kernel.

Yeah, I realized after writing this up that the vertical scrolling would have to be handled by adjusting the starting/ending Y index. Not really a problem, though.

The main issue, as Manuel mentioned, is the train.
  • Report

Yeah, I realized after writing this up that the vertical scrolling would have to be handled by adjusting the starting/ending Y index.  Not really a problem, though.

That's not what I meant. Only adjusting start and end will limit your scrolling range severely. I meant a table, which loads the next Y value.
.loop:
   tay
   ...
   lda Table,y
   bne .loop

Table:; in RAM!
   .byte 0, 2, 3, 4, 5... 158, 159, 0; start with Y = 1
Which later changes e.g. into:
  .byte 0, 2, 0, 4, 5... 158, 159, 1; start with Y = 3
  • Report
Well...Hm.

If I store the scrolling PF data in ROM, then, now that I think of it, I would just need to change the address of the PF load instruction (i.e., self-modifying code). Y could remain unchanged. Have to worry about page crossing penalties, but other than that I should be fine, I think.

Like this:
  lda PFDataInROM,Y      ;<--adjust this address outside the kernel as needed
   sta PF0
  • Report

Well...Hm.

If I store the scrolling PF data in ROM, then, now that I think of it, I would just need to change the address of the PF load instruction (i.e., self-modifying code).  Y could remain unchanged.  Have to worry about page crossing penalties, but other than that I should be fine, I think.

But how will you wrap back to the beginning of the buffer? Without wrapping, if you scroll into one direction, your buffer will move over the whole address space.
  • Report

But how will you wrap back to the beginning of the buffer? Without wrapping, if you scroll into one direction, your buffer will move over the whole address space.

:|

That's an issue, but not a big one. Unless I misunderstand.

I'd probably do it the same way I do it in my (newest) music driver: at the end of the data, I have a $FF byte followed by the address of where to reset the pointers to. Probably in the PF0 table since I could easily avoid the value $FF for displayed data:
PF0DataTable
   .byte %00000000
   ...
   .byte %00100000
   .byte $FF
   .word NextChunkOfPF0Data;use .word PF0DataTable to wrap

Or am I misunderstanding something?

EDIT: Or hmmm. Actually, probably have the label at the end of the table and the terminate data at the beginning:
  .word NextChunkOfPFData-SCREENHEIGHT
   .byte $FF
   .byte %00100110;this is the last line of this data set that will be displayed
   ...
   .byte %00110000;this is the first line of this data set that will be displayed
EndOfPF0DataTable;<--actually initially set pointer to address-ScreenHeight
  • Report

Yeah, I realized after writing this up that the vertical scrolling would have to be handled by adjusting the starting/ending Y index.  Not really a problem, though.

That's not what I meant. Only adjusting start and end will limit your scrolling range severely. I meant a table, which loads the next Y value.
.loop:
   tay
   ...
   lda Table,y
   bne .loop

Table:; in RAM!
   .byte 0, 2, 3, 4, 5... 158, 159, 0; start with Y = 1
Which later changes e.g. into:
  .byte 0, 2, 0, 4, 5... 158, 159, 1; start with Y = 3

I like it. You only have to change two bytes in your table to perform a scroll, and your table lookup only costs four cycles as compared with a dey (and in some cases you can even 'absorb' those).

BTW, using a double-line kernel can often be useful even if you're drawing some shapes at single-line resolution. If your displayed area is 170 pixels or fewer, you can put three 85-byte tables in a page. Color and shape data for both players on every scan line would take 2 2/3 pages. If you use a 'straight' single-line kernel, the data would have to occupy 170 bytes on each of four separate pages--not nearly as nice.

If some shapes are at single-line resolution and others are at double, the decision becomes even easier.
  • Report

I'd probably do it the same way I do it in my (newest) music driver:  at the end of the data, I have a $FF byte followed by the address of where to reset the pointers to.

That would work, but wrapping will cost you a lot of cycles inside your kernel then. Or do you have some clever code to do that?
  • Report

I like it.  You only have to change two bytes in your table to perform a scroll, and your table lookup only costs four cycles as compared with a dey (and in some cases you can even 'absorb' those).

Thanks, IIRC the idea comes from Manuel. Actually, for my current kernel I use a different way, which looks like this:
  ldx Table,y
   ...
Table:
   .byte 1,1,1,2,3,3,3,4,4,4,4,4,5,6,6,6...
Y is counting down from ~180 to 0 and is used for drawing sprites, X is used for indexing SC-RAM for PF writes.

Verticall scrolling is a bit more complicated that way (selfmodifying code etc.), but I save a lot of SC-RAM which makes it much easier to scroll horizontally.
  • Report

I'd probably do it the same way I do it in my (newest) music driver:  at the end of the data, I have a $FF byte followed by the address of where to reset the pointers to.

That would work, but wrapping will cost you a lot of cycles inside your kernel then. Or do you have some clever code to do that?

Hm. No clever code right now. Probably before I get into this too much more I need to figure out:
1. What the scanline resolution of the scrolling PF will be, and
2. Whether the terrain needs to be multiple screens in length or if I should just wrap a single screen's worth of data around, and
3. If it is multiple screens in length, how many.

If all the terrain data for a single level will fit in a page, then no worries about wrapping. :|

Thanks for the ideas, though!
  • Report