Jump to content
Sign in to follow this  
Cybearg

Concerns of ROM Space...

Recommended Posts

I'm currently working on a scrolling Intellivision game. I would like each level to have 10 screens (at least) so that the levels have a decent length (by my estimations, it would take between 6 and 7 minutes to complete). I want three levels per stage and a total of six stages in the game.

 

The problem is that comes to 86,400 bytes of map data alone!

 

Should I panic? What can I do to get a decent-sized game within what seem to be very strict ROM limitations? Is this not as big of a concern as I'm making it out to be, or should I panic?

Edited by Cybearg

Share this post


Link to post
Share on other sites

There's a number of solutions. Here's a start...

 

Use bits instead of bytes. Maybe you only need a few bits to determine what is at each point of the screen, instead of using all 8 bits. For instance, if there are only 16 different characters used on each screen, each character only needs 4 bits instead of 8. You've saved half your space already.

 

Encode the data differently. Maybe there's a lot of "white space" on the screen. If you list each item, that may save space. For instance, make a list that includes data such as character1,xlocation,ylocation for each character. Encode using bits. Character might take 4 bits, xlocation might take 5 bits, and ylocation might take 4 bits. That's 13 bits per character used.

 

Use compression.

 

Use random numbers starting with a known seed. Use a different seed for each screen. This might not work for all the items on the screen, but might be good for backgrounds and less important items.

 

I'm sure there are more ways besides completely laying out each screen character by character and byte by byte.

Edited by 5-11under

Share this post


Link to post
Share on other sites

You could certainly make it work uncompressed, but you'd probably end up with some page-flipping. Or, you could implement some simple forms of compression.

 

Let me see if I can recreate your math:

  • 10 "screens": I assume you mean 20 x 12 x 10 = 2400 display characters of level data
  • 6 stages x 3 levels/stage = 18 levels total
  • 18 * 2400 = 43200 characters
  • 2 bytes / display word = 86400 total bytes

Is that how you came to the numbers?

 

For one, you could probably compress down to bytes instead of storing words for each display element. Each graphic is likely to show up in only a few colors, so have an indirection table that expands things for you. You could even use a different indirection table for every level so that you could tune the encoding differently based on each levels' needs. (I do something like this in Space Patrol, actually.)

 

Just cutting the data in half with no further compression gets you down to 21K words, which, while large, is still quite manageable. You can have games up to ~50K words without page flipping if you don't use any RAM expansion. Shrinking your map data down to 21K words, leaves you another 29K words to play with for music, graphic tiles and game logic.

Share this post


Link to post
Share on other sites

Use bits instead of bytes...

Encode the data differently...

While this is technically correct that there is a lot of wasted bits, I don't see how that's particularly useful. It's not like you can just mash bits together and get coherent data; the position of those bits encodes some of the information.

 

Sure, I might only be using 13 out of 16 bits, but what am I going to do with the remaining 3 bits of that word? I can't just begin another word part-way through an existing word and get any coherent data out of that.

 

Use compression.

Are there any ASM algorithms that could decode encoded data fast on the fly? If so, that would be great, but I have no idea how to encode or decode words.

 

Use random numbers starting with a known seed.

Well, the game's design isn't really based around randomness. Pretty much every level is intentionally designed with particular enemies placed in a precise location. It doesn't run off of a seed.

 

I'm sure there are more ways besides completely laying out each screen character by character and byte by byte.

Wish someone had told me that before I made a program to help me to exactly that. :P

 

 

You could certainly make it work uncompressed, but you'd probably end up with some page-flipping. Or, you could implement some simple forms of compression.

I'm totally okay with page-flipping, whatever that means! How do I do that with IntyBasic? Whatever it takes to make this work with as few sacrifices as possible.

 

Let me see if I can recreate your math:

  • 10 "screens": I assume you mean 20 x 12 x 10 = 2400 display characters of level data
  • 6 stages x 3 levels/stage = 18 levels total
  • 18 * 2400 = 43200 characters
  • 2 bytes / display word = 86400 total bytes
Is that how you came to the numbers?

 

Exactly.

 

For one, you could probably compress down to bytes instead of storing words for each display element...

So, for instance, there would be:

word_table:
   data $F803, $C905
   ...

locations_table:
   data 0, 5, 8, 20, ... $F03, $F93...
   data 3, 9, 13, ... $801 ...
Or something along those lines? A problem is that I have a scrolling game, so the correct tile data for a column has to be read in at just the right time. This table scatters that data around and would, I'd think, require a mess of processor time and memory to unjumble it all in real time for new cards to be fed in.

 

Just cutting the data in half with no further compression gets you down to 21K words, which, while large, is still quite manageable...

How do I do compression?

 

The Atari 2600 and the 7800 both have options for chips that are 128-512+ kb with (from what I understand) no or little trouble in the process. Is there no option like that--just burning the ROM onto a bigger chip that is dirt-cheap these days?

 

What's all this stuff about pages and how does that work? What's the catch?

 

For the record, each screen will have more or less this level of detail:

post-34988-0-28011300-1413432862_thumb.png

 

I'm not sure if that's considered dense or not, but most of the game will incorporate only a handful of variations on mostly the tiles you see displayed here.

Edited by Cybearg

Share this post


Link to post
Share on other sites

I'm totally okay with page-flipping, whatever that means! How do I do that with IntyBasic? Whatever it takes to make this work with as few sacrifices as possible.

 

Honestly, I'm not exactly sure what the best way would be at the moment. If you look at the cart.mac I posted previously, it provides some memory maps that go up to 118K words, using page flipping. The high level view is this: You'd put all of your per-level level data onto the page-flipped sections. Upon entering a level, you'd flip in the pages for that level (since you don't need to see the level-specific data for the other levels).

 

How to do that in the context of IntyBASIC? I suspect you'd need some ASM directives to arrange for the data to be in the paged segments, and some POKE statements to flip the pages.

 

 

 

I'm totally okay with page-flipping, whatever that means! How do I do that with IntyBasic? Whatever it takes to make this work with as few sacrifices as possible.

 

Exactly.

 

So, for instance, there would be:

word_table:

data $F803, $C905

...

 

locations_table:

data 0, 5, 8, 20, ... $F03, $F93...

data 3, 9, 13, ... $801 ...

 

Ok, I'm going to write it in terms of C code, as that's the easiest way for me to express myself concisely:

const uint16_t decode_table[256] = 
{
    0xABCD, 0x1234, 0xAABB, ... /* all of the unique BACKTAB patterns that appear in the level */
}

const uint8_t level_data[10 * 20 * 12] =
{
    0x10, 0x20, 0x12, 0x13, 0x13, 0x13 ... /* each of these indices refers to an entry in the decode table above */
};

/* Decode a screen's worth of data.  Assume a horizontal scroller, and 'c_ofs' says how far we've scrolled over. */

    for ( r = 0; r < 12; r++ )
        for ( c = 0; c < 20; c++ )
        {
            byte = level_data[ r * 200 + c + c_ofs ];
            backtab[ r*20 + c ] = decode_table[ byte ];
        }

The basic idea is that each byte in your level data refers to what word to pull out of the decode table. Implementing that in ASM is actually pretty cheap.

 

Is your game a horizontal scroller, vertical, or mix?

 

 

Now, in the real ROM, you'd want to pack two bytes in each word, so that does add a small complication. But it's not a huge complication.

 

 

 

How do I do compression?

 

Well, it'll really depend on the nature of your level data and how it's exposed to the player. (ie. are you horizontal scrolling, and need to only expose one new column at a time on the right? Or do you need to go right and left? Or all four directions?)

 

It looks like from your screen shots that you might have vertical structures that lend themselves to a really simple "run length encoding." I used a form of RLE in Space Patrol that worked out super well. The level data for Space Patrol is quite compact.

 

 

 

The Atari 2600 and the 7800 both have options for chips that are 128-512+ kb with (from what I understand) no or little trouble in the process. Is there no option like that--just burning the ROM onto a bigger chip that is dirt-cheap these days?

 

What's all this stuff about pages and how does that work? What's the catch?

 

Well, you can only get to all that ROM with page flipping, especially on the Atari 2600. The 2600 only has 2K bytes of address space mapped for the cartridge port, as I recall. To get to more than that, you have to page flip.

 

Page flipping generally involves two things:

  • Mapping multiple ROM segments to the same range of addresses
  • Setting up a mechanism to tell the cartridge which ROM segment to make visible at any given time. (At any given time, only one ROM can be visible at any given CPU address.)

On the Intellivision, the simplest page-flipping scheme (used by the ECS, WSMLB, Go For The Gold and some other unreleased titles) involves writing a special word to a special location to flip a 4K ROM segment to a different page. (4K words, that is.) If you go down that path, I'd be happy to explain that mechanic further.

 

The main thing to watch out for, though, is that while one page is flipped in, all other pages at the same address range are flipped out. So, you need to take some care to make sure you don't need the stuff on the other pages while they're flipped out. This is why I suggested way above that if you go down this path, an obvious way to set yourself up is to use the page-flipped sections to hold level data, so that you can flip to the segment with the current level, and ignore the other levels' data.

 

It's much trickier to put code on page flipped segments, so avoid it if you can. (Sounds like you should be able to.)

Share this post


Link to post
Share on other sites

Whooo boy. Someone needs to take this thread and turn it into an intro course in bitmapping, RLE, and a few other techniques that I am NOT the nest person to be explaining.

 

Cybearg - let me give you a VERY poor explanation of some of what these guys mean by "compression" and whatnot. In essence, see all those black squares? You don't need to use an entire 16 bit value to represent each of them. You can have a variable(s) or table that says "tiles 1, 2, 3, 4, 16, 62, 87, and 99 use this card". Which can be stored in a much smaller value than 16 bits per tile. Now, you can still use your mapper to CREATE the screens - but what they're saying is that you don't need to use its final output to STORE them. Really what you're looking at are a bunch of fairly elegant math routines designed decades ago, to get more information out of less. The ALGORITHM really is what determines what goes where on the screen, using a small amount of data to direct it. It's the same with the suggestion of a random generator with a seed - using a specific seed means that by definition, you're NOT making a random level. It's pretty freaky shit but when it works, it's amazing. I once played with a fully 3D textured surface generator of the surface of Mars (and I mean the bulk of the planet) that only used like 4KB of data to store it. There was hella complicated math behind it but the actual data set was ridiculously small.

 

RLE, or Run Length Encoding, is another similar trick. If you have 6 black squares in a row, you do not need 6 words (or even bytes) to store this. You simply say "this tile, please make 6 of them" (which you can fit into a byte easily) and let the program do its magic. Repeat as necessary. It's a form of "compression" as well - it's actually what Color Stack mode kinda does, albeit with limited capabilities. They're not talking compression like actually compressing data and decompressing on the fly in the way we think of it today, although in essence that's what's going on. But it's not "here's some data, run this generic compression algorithm on it" in the sense of say ZIPing a file. It's specific compression designed around your data set.

 

And that is my piss poor attempt to bridge the gap between the math geeks here, and us common folks. My schoolin' on this is too many years in the past.

Share this post


Link to post
Share on other sites

No, that makes sense, freeweed. Same to you, intvnut. However, I'm sure that these compression techniques require some ASM that I have no idea how to code. Maybe nanochess is reading this and can offer suggestions or encouragements for planned IntyBasic support of this kind of thing.

Luckily for me, I made the program that I'm writing the maps with, so getting it to export compressed data shouldn't be too difficult. :) I just don't know how exactly to use it in the most optimally-efficient way. Heck, maybe the compression could be combined with the page-flipping?

By the way, by "page-flipping," are you referring to "bank switching"? Not that it matters, but banks in the 2600 are up to 4k. I had to work a fair bit with them in the development of Piñata (sort of), and it wasn't a problem. Having level data in different banks that I need to switch to, read out the bytes, then switch back to the main program to continue? Pff, piece of cake from a software design standpoint. I have no idea of the complications and process from a software architecture standpoint, though. If it's like the way batariBasic does it, it's as simple as specifying a subroutine and a bank to jump to, then returning from it.

 

Oh, and the game is horizontal scrolling from left to right only; no need to worry about going backward or up/down.

 

What is the practical size available to me for the Intellivision/IntyBasic without page flipping, and what is available WITH page flipping? Does non-page flipped Intellivision work on 8kb banks as well, or is there some standard 16k bank for non-page flipped and a smaller version for page flipped?

Edited by Cybearg

Share this post


Link to post
Share on other sites

I'm currently working on a scrolling Intellivision game. I would like each level to have 10 screens (at least) so that the levels have a decent length (by my estimations, it would take between 6 and 7 minutes to complete). I want three levels per stage and a total of six stages in the game.

 

The problem is that comes to 86,400 bytes of map data alone!

 

Should I panic? What can I do to get a decent-sized game within what seem to be very strict ROM limitations? Is this not as big of a concern as I'm making it out to be, or should I panic?

Per my estimations, 240 characters per screen x 3 levels x 6 stages = 43200 words.

 

Now, you are probably limited to a few different tiles per screen and enemy markers (or you can put these in another DATA table)

 

So using only one byte (keeping two per word) would get you to 21400 words that you can keep very easily in your game. (leaving you another 21400 words for your game)

 

The most easy thing is to keep a reference table for your level and use it to draw the column:

 

main_loop:
  #offset = #offset + 10 ' each 8 pixels


draw_column: PROCEDURE
  ON stage GOTO drawstage1_1,drawstage1_2,... and so

  #d = #offset
  FOR C=19 TO 219 STEP 40
  PRINT AT C,map1_1(stage1_1(#d) % 256)
  PRINT AT C+20,map1_1(stage1_1(#d) / 256)
  #d = #d + 1
  NEXT C
  RETURN
  END

map1_1: DATA '...your STIC display words for each tile...

stage1_1: DATA $0102,$0304,$0506 '... and so

Truth to be told I don't know how efficient will it be, but I think it will work :)

Share this post


Link to post
Share on other sites

Truth to be told I don't know how efficient will it be, but I think it will work :)

What about page flipping in IntyBasic?

Share this post


Link to post
Share on other sites

What about page flipping in IntyBasic?

 

Not yet here, I need to get my hands in real hardware, specifically the LTO-Flash cartridge.

Share this post


Link to post
Share on other sites

Luckily for me, I made the program that I'm writing the maps with, so getting it to export compressed data shouldn't be too difficult. :) I just don't know how exactly to use it in the most optimally-efficient way. Heck, maybe the compression could be combined with the page-flipping?

 

Using a program to generate the data is a pretty good idea. Should give you the flexibility to change it later.

 

Whether you use page-flipping is orthogonal to how you encode it. :-)

 

 

 

By the way, by "page-flipping," are you referring to "bank switching"?

 

Page-flipping / bank-switching: to-MAY-to / to-MAH-to. :-) Both are referring to the same concept: Multiplexing multiple memories at the same range of addresses. In the Intellivision space, I tend to use the term "bankswitch" when referring to how the Intellicart does it as it uses the keyword [bankswitch] in the .CFG file to configure it. I use the term page-flip to refer to how Mattel did it in the ECS, WSMLB, and friends.

 

These days, I tend to use the Mattel style page-flipping. It's fairly straightforward, and in theory allows for games up to 768K words (1.5Mbytes), if you use all 16 pages on $2xxx, $5xxx, $6xxx, $7xxx, $8xxx, $9xxx, $Axxx, $Bxxx, $Cxxx, $Dxxx, $Exxx and $Fxxx. And that's ignoring the tiny 2K span at $4800 - $4FFF. You could even extend it further to make games arbitrarily large, up to the capacity of whatever storage you want to pay for in the space of a cartridge.

 

The only constraint is that you can only have 48K words visible at one time across all the page flipped segments.

 

JLP supports games up to around 118K words (236K bytes). I say "around", because you can go higher than that if you have significant amounts of less-than-16-bit data. LTO Flash has 1MB RAM (512K words) on board.

 

 

Not that it matters, but banks in the 2600 are up to 4k. I had to work a fair bit with them in the development of Piñata (sort of), and it wasn't a problem. Having level data in different banks that I need to switch to, read out the bytes, then switch back to the main program to continue? Pff, piece of cake from a software design standpoint. I have no idea of the complications and process from a software architecture standpoint, though. If it's like the way batariBasic does it, it's as simple as specifying a subroutine and a bank to jump to, then returning from it.

 

It sounds like bAtariBASIC knows something about bank-switching, then, and has built in support for it. IntyBASIC currently doesn't even know much about the ROM memory map. :-) (It does know where scratch and system RAM are.)

 

The main thing is that at any given time, you need to be able to see both the code you're running and the data it needs to operate on. Other data and other code can be safely switched out.

 

Note that "the code you're running and the data it needs" includes the interrupt handler and any data it requires as well. :-)

 

 

 

Oh, and the game is horizontal scrolling from left to right only; no need to worry about going backward or up/down.

 

That adds some flexibility. For example, if you run-length encode by column (ie. "next N characters are all X"), each encoded column will end up being a slightly different length. But, to keep scrolling rightward, you only need to know where you stopped decoding the previous column to know where the next column starts in the data. Space Patrol makes heavy use of that principle.

 

If you had needed to go right and left, you'd need to track more information so that you could decode columns on either edge of the screen. For example, an index table telling you where each column starts in the data. That eats away at the compression ratio.

 

 

 

What is the practical size available to me for the Intellivision/IntyBasic without page flipping, and what is available WITH page flipping? Does non-page flipped Intellivision work on 8kb banks as well, or is there some standard 16k bank for non-page flipped and a smaller version for page flipped?

 

Without page flipping, you can get up to around 50K of ROM. With page flipping... well see above. The sky's the limit. ;-)

 

If you go with Mattel style page flipping, the pages themselves are 4K words (8K bytes). In each 4K address span, you can have up to 16 pages. Each 4K span flips independently of the others. It's quite straightforward and flexible.

 

Here's a quick example: Suppose you didn't compress a thing, and you put each stage (3 levels) in its own distinct set of pages. A single stage is 7200 words. You could set up a memory map like this:

 

  • $2000 - $2FFF, $5000 - $6FFF, $7000 - $7FFF, $A000 - $BFFF, $C100 - $CFFF, $F000 - $FFFF for game code, not page flipped. That's ~32K words (~64K bytes) of non-level data and code.
  • $D000 - $DFFF PAGE 2, $E000 - $EFFF PAGE 2: Stage 1 level data. (8K words, 16K bytes)
  • $D000 - $DFFF PAGE 3, $E000 - $EFFF PAGE 3: Stage 2 level data. (8K words, 16K bytes)
  • $D000 - $DFFF PAGE 4, $E000 - $EFFF PAGE 4: Stage 3 level data. (8K words, 16K bytes)
  • $D000 - $DFFF PAGE 5, $E000 - $EFFF PAGE 5: Stage 4 level data. (8K words, 16K bytes)
  • $D000 - $DFFF PAGE 6, $E000 - $EFFF PAGE 6: Stage 5 level data. (8K words, 16K bytes)
  • $D000 - $DFFF PAGE 7, $E000 - $EFFF PAGE 7: Stage 6 level data. (8K words, 16K bytes)

 

You might ask why I started with page 2? If you have an ECS unit attached, it has ROM at $Exxx PAGE 1, so it makes sense to avoid it to avoid compatibility issues. Pages 2-7 give you 6 consecutively numbered pages all to yourself.

 

I avoided putting paged ROM at $Fxxx in this example, because of how the page-flip mechanism works, and how memory is aliased on the Intellivision. You write the value $xA50 + page# to location $xFFF to flip the ROM in the segment $x000 - $xFFF. So, to flip $Fxxx, you write $FA50 + page to location $FFFF. Location $FFFF aliases location $39FF, which happens to be the last location of GRAM.

 

The ranges $2000 - $2FFF and $7000 - $7FFF actually should be paged also, but not flipped after initialization, also to avoid ECS compatibility issues. (There's some other minor squirrely details, but we can tackle them when the time comes. Or avoid those ROM segments entirely if you don't actually need them.)

 

The ROM image above would be 80K words / 160K bytes if you used everything. Quite manageable.

 

(The eagle-eyed will notice I left out $8000 - $9FFF. You could put ROM there. Alternately, you could put RAM there. That's where JLP puts its extra RAM by default, and I think Bee3 followed suit.)

Edited by intvnut

Share this post


Link to post
Share on other sites

Well, thanks to everyone for the information! It's a relief to hear that I have options.

 

For the time being, I'll juts continue development as is, testing the levels one by one. I like the idea of possibly combining page flipping with compression to maybe get longer levels in. In any case, I'll be waiting on IntyBasic to offer native page flipping support, as that seems to be the crux of things.

  • Like 2

Share this post


Link to post
Share on other sites

Well, thanks to everyone for the information! It's a relief to hear that I have options.

 

For the time being, I'll juts continue development as is, testing the levels one by one. I like the idea of possibly combining page flipping with compression to maybe get longer levels in. In any case, I'll be waiting on IntyBasic to offer native page flipping support, as that seems to be the crux of things.

 

 

Not yet here, I need to get my hands in real hardware, specifically the LTO-Flash cartridge.

 

 

FWIW, AS1600 and jzIntv support page flipping today, if you want to get a head start. Page flipping is a pretty low risk thing to test in the emulator.

 

I suppose I should post the absolute latest jzIntv and AS1600 soon. (Maybe this weekend?) I was out of commission last week with the flu, and this week I've been catching up on everything from the week before. So much for my plan of taking a week off to catch up on things. :-P

 

The assembler now has support for page-flipped ROMs, which is kinda relevant ;) and a number of other minor fixes and improvements. In jzIntv, there's been some fixes to PAL timing (still not super accurate, but much much closer in tests I made locally now that I'm set up for it), page flipping (there were bugs when the page wasn't "full," something I hadn't tested until AS1600 started spitting out ROMs with page flipping), Scale2x/3x/4x, some preliminary support for save/restore on game state, and so on.

Edited by intvnut
  • Like 2

Share this post


Link to post
Share on other sites

If I were doing a side scrolling game, I would create some kind of "large tiles" to build the screens with - say 4X4 character tiles, or 8x8, or 8x12?

 

Then I would string these large tiles together like model train sections to build the levels.

 

This might reduce the "visual variety" of the levels, but it would save a lot of space, I think.

 

Catsfolly

  • Like 1

Share this post


Link to post
Share on other sites

If I were doing a side scrolling game, I would create some kind of "large tiles" to build the screens with - say 4X4 character tiles, or 8x8, or 8x12?

 

Then I would string these large tiles together like model train sections to build the levels.

 

This might reduce the "visual variety" of the levels, but it would save a lot of space, I think.

 

Catsfolly

 

If you're only exposing one new column at a time, though, don't you need an offscreen buffer or extra tracking variables to know how much of each large-tile is exposed?

 

I have something like that in SP. I record in the level data where each rock or crater begins, and that initializes separate counter that tracks how much of the object I've revealed. As the screen scrolls, the counter moves through the object, exposing it incrementally. These elements are 2 tiles high and arbitrarily long. (There's a termination bit in the encoding.) But, since SP worlds are effectively 1-D encoding-wise, I only need one such counter.

 

For a 20x12 screen, you could conceivably need up to 12 such counters, although obviously fewer if your tiles are all 2 tiles or taller.

 

A coworker of mine, Mike Denio, said that when he was writing Captain Comic for the NES, he spent some time w/ Color Dreams examining Super Mario Bros. Apparently it uses a compressed encoding along those lines. Changing a byte here or there would bring in or remove major structural elements, and they never really bothered to work out the details. The NES has the luxury of a display buffer that's 2x the visible space IIRC. You could build the map by parts off-screen, which makes that approach easier. Mike told me he went with uncompressed maps for Comic to make programming simpler, because ROM was cheap enough by that time.

 

(Fun fact: Mike and I also both attended the same college, although several years apart.)

Edited by intvnut
  • Like 1

Share this post


Link to post
Share on other sites

And if Wikipedia is correct, I now know where you work :P

Creeper. :P

 

I see the benefit of what's being discussed. I may well use it in future games, but for the time being, tile-by-tile detail is a necessary part of making the levels feel fresh and interesting, particularly since the shape of buildings drives the core level design and influences gameplay in the primary movement mechanics.

Edited by Cybearg

Share this post


Link to post
Share on other sites

I've pondered it some more and, after further playtesting, the scrolling speed I was playing at just was too slow to be satisfying. To make it fun, I've had to double the scroll speed, which means that each 10-screen level that before lasted ~7 minutes will only last 3 and a half. That's just unacceptable for gameplay.

 

Even with compression, there's no way I can get a decent game size for a scrolling game (that doesn't rely on procedural generation or simplified game fields) without the size benefits of page flipping.

 

Consider this an extremely strong "pretty please," nanochess. :)

Edited by Cybearg
  • Like 1

Share this post


Link to post
Share on other sites

If I were doing a side scrolling game, I would create some kind of "large tiles" to build the screens with - say 4X4 character tiles, or 8x8, or 8x12?

 

Then I would string these large tiles together like model train sections to build the levels.

 

This might reduce the "visual variety" of the levels, but it would save a lot of space, I think.

 

Catsfolly

 

I think that's similar to how GroovyBee implements the procedural level generator for his Mars Minis game. You have a set of pre-built, interlocking pieces that they all match with each other, and either follow some simple map encoding to put them together, or randomly build the level as you go.

 

That is also how I build Christmas Carol levels, and a propos to this discussion, the scrolling screens for the Practice Menu. I have what I call "Ice Cube Sets" composed of 6-tiles to be used on the maze. There are 8 of these, so they can be encoded in three bits, but I allocate a full byte for it (just in case ;) ). The maze encoding includes an "envelope" that describes which Cube Set to use (a number from 1 to 8), and then a map that describes which cubes go where (each one a number from 1 to 6).

 

There is also a list of COL/ROW positions where the presents go for each level, and another for the Snowflakes. And finally, the COL/ROW position where the sprites will start on that level. (These columns and rows are on the "virtual map," which is a 4x4 tile matrix describing the tunnels of the maze.)

 

During level initialization, while the screen is blanked out (for at least one frame, and no more than two) all this data is loaded and decoded to draw the screen. The screen is drawn once and persisted until the next level, so there is no need to decode the data again.

 

During game-play, collisions with background objects (e.g., Presents and Snowflakes) by comparing the sprite's "virtual map" position to those in the lists.

 

The scrolling is done with a similar screen encoding. There is a counter that keeps track of which column we are in, and which offset within that column. When the offset counter reaches 8 (a full tile), we find the next column in the screen map using the column counter index, then decode the column and draw each tile in the BACKTAB. To be sure, the GRAM is loaded prior to all this, so that all necessary "Ice Cube Sets" and custom fonts and background tiles have already been loaded by the time we scroll.

 

-dZ.

Edited by DZ-Jay

Share this post


Link to post
Share on other sites

I've pondered it some more and, after further playtesting, the scrolling speed I was playing at just was too slow to be satisfying. To make it fun, I've had to double the scroll speed, which means that each 10-screen level that before lasted ~7 minutes will only last 3 and a half. That's just unacceptable for gameplay.

 

Even with compression, there's no way I can get a decent game size for a scrolling game (that doesn't rely on procedural generation or simplified game fields) without the size benefits of page flipping.

 

Consider this an extremely strong "pretty please," nanochess. :)

 

I've promised some LTO-Flash support to intvnut, but I need to get the cartridge in my hands before anything can be done in IntyBASIC.

Share this post


Link to post
Share on other sites

Even with compression, there's no way I can get a decent game size for a scrolling game (that doesn't rely on procedural generation or simplified game fields) without the size benefits of page flipping.

 

 

I don't think you require page-flipping for this. I'm sure you can make a fantastic scrolling game with plenty of details with just creative encoding and use of the ROM available, and some compression. Of course, you will need IntyBASIC to support more than the 4k or 8K that it supports right now, but you can get away with it using the the ORG assembly directive inline.

 

Make sure you understand the difference between utilizing more than one ROM segment within a game and "page-flipping" or "bank-switching." There's upwards of 42K of ROM available.

 

-dZ.

Share this post


Link to post
Share on other sites

 

I've promised some LTO-Flash support to intvnut, but I need to get the cartridge in my hands before anything can be done in IntyBASIC.

Fair enough.

 

 

I don't think you require page-flipping for this. I'm sure you can make a fantastic scrolling game with plenty of details with just creative encoding and use of the ROM available, and some compression. Of course, you will need IntyBASIC to support more than the 4k or 8K that it supports right now, but you can get away with it using the the ORG assembly directive inline.

 

Make sure you understand the difference between utilizing more than one ROM segment within a game and "page-flipping" or "bank-switching." There's upwards of 42K of ROM available.

 

-dZ.

I'm really not clear on what you're talking about. How do I utilize these other ROM segments, and what are they?

 

The problem is, even with compression (at least the kind recommended to me by nanochess--if there's a better form, I've not seen it mentioned) is, since my game is a side-scroller that moves at a fixed rate, 1 pixel every 8 cycles, I can calculate how long it a level will take to play:

8 frames / pixel * 8 pixels / card * 20 cards / screen * 10 screens / level = 12800 / (60 frames / second) / (60 seconds / minute) = 3.555 minutes of gameplay per 10 screens of level data. And since there are (approximately) 240 bytes per screen when using compression, each level is 2,400 bytes.

 

The plan was for 3 levels per stage and 6 stages in the game, putting the entire game at just a little over an hour to play--and this isn't through speed-running, since the game moves at a fixed pace.

 

I really don't feel like 3.5 minutes for a level and 64 minute for an entire game is a good value. To get a minimum acceptable size, I would need to double level sizes, which means double the time to develop and double the ROM space required (4,800 bytes per level * 18 levels = 86,400 bytes for stage data). That's a fair bit more than the 42K words I have available for the entire game.

 

So that means either the game needs to be significantly re-designed to make better use of its limited resources to get more gameplay out of it, or I need some way to hugely boost the amount of ROM at my disposal.

Edited by Cybearg

Share this post


Link to post
Share on other sites

86,400 8-bit bytes = 43,200 16-bit words

 

And that's without any compression at all. I'm sure people in this forum can help you manage that.

 

Bank-switching is fine and all, but the complexities of managing it may not be warranted. It's not a "magic-bullet."

 

Moreover, I cannot stress how much 42K 16-bit words is in practice for a 1980s console. Remember, the best games we played back then did not exceed 8 or 16 thousand words.

 

There are some very knowledgeable people in this forum. I say, post your encoding algorithm, preferably some code or sample data structures, and lets see what can be done to optimize it.

 

dZ.

Share this post


Link to post
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...
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...