Hacker News new | past | comments | ask | show | jobs | submit login

Ex-C64 games coder here: you are are correct - no, you couldn't relocate/page-flip the colour map, like you could the character map. So you had to update it all somehow on the required frame.

The fastest technique I saw for updating the colour map in a single go, was to have the whole thing as a huge block of immediate mode load-stores, then one could 'scroll' the data across the LDA instructions within that code, in advance, over n-frames, then call this self-modified code block when one did the character screen flip (immediate load-stores was faster than load-stores from colour ram). e.g.

  scroll_splat_colour:
    LDA #$00  # colour data for char
    STA $D800 # colour ram
    LDA #$00
    STA $D801
    # etc., for every visible char onscreen in scrolling area
And one would be updating/scrolling those values loaded into the A register, in chunks over previous frames, similar to:

    LDA scroll_splat_colour+6
    STA scroll_splat_colour+1
    LDA scroll_splat_colour+11
    STA scroll_splat_colour+6
    # etc., for every lda/sta in the above
Perhaps not the clearest explanation, but hopefully enough to communicate the idea.

FWIW, I didn't invent that technique, it was an improvement Jon Williams made to my code, whilst we both worked for Images Software (now Climax). Not sure where he got it from, maybe he invented it himself, maybe he cribbed it from elsewhere.

Related: I thought sprite multiplexing was awesome, and there were quite a few tricks there too to get it performant. But that's another far more complex topic.




Another "obvious" trick is to narrow the playing field but animate the rest, and then safe cycles by a combination of bands that requires less updates and sprites. E.g. Pole Position is a classic example, where the graphics covers most of the screen, but only about half actually has gameplay. The rest consists of a very narrow band of mountains, and a couple of bands of clouds. I haven't looked at what they did for Pole Position, but that pattern of the actual gameplay being constrained to a much smaller portion of the screen than what looks like the playing area is pretty common.


Yeah, compiled graphics and compiled colour tables, also, a routine that could self-modify code in regions of RAM to do the colour table writes. A slow set-up function at level start would build the code to be JSR'd later in the level. We did that on a few games on the C64 and the Speccy and Beeb and Atari. Later used the same techniques in DOS on PC. And of course, doing the same tricks but with D0 through D7 and A0 through A6 on Atari ST and Amiga. Also doing "stuff" in zero page because the address loads were shorter. And avoiding 256-byte page boundaries where possible because of the cycle penalty.


> A slow set-up function at level start would build the code

Interesting, and good thinking :)

IIRC, when we used this technique on the C64, we didn't build the code during init at runtime, we actually built the code in the dev environment, using macros, so it got built at assembly/compile time. So we skipped the small time hit at runtime init, at the expense of a slightly longer load time for the user (and a tiny bit longer on our assembly/compile times, although that was fairly negligible cos we were building on PCs).


Yeah, we did macro builds in the development environment too, but I also had access to doing some nifty and complex macro and pre-compiled graphics code by making use of BBC BASIC to do the manipulations. Like if you were doing soft sprites, pre-compiled functions to auto-shift the sprites on the X axis without having to do any kind of ROL/ROR and handling carry bits. One of my colleagues wrote really nice set of functions where you could specify that "this sprite should have eight shifts created during setup, go create the necessary loops, toot-sweet!" or "this fast moving bullet sprite can only appear on four pixel boundaries, only needs two shifts, and can be pre-compiled at build time."

There were other functions that we all contributed to for doing horizontal and vertical flips and arbitrary rotations and a ton of stuff for collision detection boxes and bind points for weapon pickups and emission points for bullets being launched, muzzle flash, or shell casings ejected from the weapon. Tons of what was effectively dynamic macro code where you just set up a table of stuff you wanted included, and some data about how certain sprites should be handled.

My development environment was a BBC Micro Model B with a macro assembler and double-sided/double-density dual 400KB floppy drives attached - 800KB of storage, which let me assemble the code from multiple pieces. Later I had a 20MB HDD. The BBC Micro could squirt the code over to the C64 via the Beeb's 1MHz Tube IO bus straight in to the C64's cartridge port. Instant load on the C64 effectively. Also had the same setup for the ZX Spectrum, though when I worked at a different company, we used RML 380Z machines IIRC, and everything ran over a shared network.


Nice tricks! I never did much with soft-sprites on any platform really.

One C64 game I worked upon did a bunch of interesting similar kinds of tricks — flips in both axis, plus the stored graphics only used a partial area of the h/w sprite, so I could pack the graphics in advance, and copy them out every frame at runtime — but only for the main character sprite.

My first 'proper' C64 dev environment was actually a BBC B, as I mentioned in another reply — almost identical setup to yours, but without the hard disk. A much better setup than just working on a single machine! After that, we used PCs with PDS cards.


Oddly enough Andy Glaister, creator of the PDS cards, and I, (Andy is two months younger than me) have very similar early careers of creating video games, heading in to local computer shops and buying C15 tapes, then duplicating them, photocopying the labels, and collecting some nice royalties for an 11-yr old. We had never met up until we both independently moved to the US and our paths crossed for a short time (Activision, other companies). Life is weird.

I'll go hunt for your other comments down thread, seems you and I also share some disconnected history of developing games.


Interesting, cheers.

I did a brief stint at Software Studios / Electric Dreams (in Southampton) — who were owned by Activision — in the late 80s. And then I did some work (via Images Software) for Activision (in Reading), a little later in the 80s. Briefly met quite a lot of well-known (better known than I, anyhow) devs during that time.

I think I recall meeting Andy Glaister at some point (though not at Activision), but I might be wrong: his name was often mentioned in our office because we (Images s/w) were dealing with PDS quite a lot. But if I did meet him, it was only very briefly, and he likely wouldn't remember me. Him and our boss (Karl Jefferies) seemed to have quite a few meetings.

I think the early / home computer games dev world was actually kinda quite small (in the UK), well, fairly tightly networked — lots of folk knew one another, or were just a couple of friend-network links away. It seemed quite commonplace to meet other devs, usually during what is now called 'crunch time' towards the end of a project, in the publisher's office. I still have memories of sleeping under various desks, in various offices, on various projects.

— Life is indeed weird!


I thought I remembered the name Jon Williams, so I looked it up on Lemon64... and it seems that you and Jon worked on one of my favorite games as a kid, C64 Back To The Future 2! Somewhere around here I still have my genuine boxed retail copy. I remember it as one of the few games I was absolutely determined to complete to the very end. I might have to break out an emulator and give it another play for nostalgia (still have my C64 too, but haven't turned it on in a long time). Thanks for working on that, it made the little-kid version of me very happy!


Thanks for the memory! And I'm glad to hear you liked the game :)

IDK if it's a game that really stands the test of time, but having worked on it always kinda skews one's view: it's hard to be objective.

Yeah, we both worked on C64 BTTF2. Although we occasionally talked and shared a bit of code when we were working on a few other separate projects too. He came to Images after I'd already been there for a while, so he got free rein to use any code I previously written for the company, so we talked quite a bit, and he'd always discuss how he was coding stuff, and share any improvements he'd made. Nice guy, and a good coder.

— Funny thing is, I never received a boxed copy of BTTF2 myself, heh. That was actually a really common thing, on a lot of games. Most of them in fact :/


> # etc., for every visible char onscreen in scrolling area

For every changed char. (which is sometimes more and sometimes less)

You could do them in order but if you're using only a few characters you need only 1 LDA for each char. (How to do this is left as a creative exercise for the reader)


But the overheads of tracking which characters might have been changed here completely outweighed simply scrolling / updating the whole thing. The code becomes too involved in tracking changes, and fudging about with- / rewriting- the splat code.

You can leave it as 'a creative exercise for the reader', but that's because you can't solve this for the generic case (i.e. any map the graphics artists might give you) in less cycles than simply dealing with each and every character, which is the worst case.

Processing that many bytes, and doing comparisons and extra branches, simply becomes overheads, and, very quickly, your code is slower than simply updating / scrolling everything simply.

For the colour splat routine, having a giant, pre-assmebled block of immediate-mode load store pairs for every character is as optimal as it gets — and handles all cases — on the C64, you only have a frame to update the colour RAM (because it cannot be relocated/paged), and you are generally chasing the scan beam to move that much data before the next frame.

You don't have the luxury of having extra cycles to re-write that block of code at runtime, and rewrite the code that scrolls the data within that code, nor do you have the luxury of having enough spare cycles to be comparing data, and branching conditionally depending on if it has changed or not.

Perhaps you misunderstand the technique I describe, or perhaps you under-estimate the overheads required to perform what you describe. Or perhaps both.


for example:

say we use only 4 chars and repeat them in the same order

then we only have 4 pre-baked transitions.

You could then swap all 4 characters in all 4 positions for free.

I confess I was a bit amused when you wanted to give the graphics artist complete freedom.


I agree with you. So many C64 games have plenty of restrictions on the art that are very clearly a result of cycle and memory budgets.

Other tricks to reduce transitions too.

Say you have a cityscape where the map is a road with assorted buildings and street level stuff. The road itself might never change colour. Assorted stuff low down in the playing field might. You might want building stretching the full height of the screen, but you can avoid full height colour transitions by demanding that the graphics never go directly full height from one colour too another. Splitting the transitions by requiring set-backs and "air" or colour consistency for part of the buildings might well let you reduce the cost of setting the colours significantly.

E.g. I have no idea if Cobra took advantage of this, but on a hunch I just sped through a long-play video of it, and I don't think there are any full height transitions from one colour to another, and there are bands where the colour never changes within a level. Buildings overlap, so most colours are either "add a bit" or "remove a bit", and you if you needed (Cobra is simple enough they probably didn't) I'm pretty sure you could beat the generic case both on speed and size by baking a few small transition functions even with the cost of having to pick the transitions.

Akin to using fixed bands of same colour at the top or bottom, possibly accented with a couple of multiplexed sprites, another "cheap" trick that'd limit the graphics artists a bit but wouldn't do much in terms of appearance would simply be to require colour changes only every few rows near the top of the screen. E.g. let those buildings (or whatever) extend to the top, but require the top floors to stick to the same colour. Now you can reduce e.g LDA/STA/LDA/STA/LDA/STA to LDA/STA/STA/STA and similarly reduce your inlined scroll code.

E.g. Cobra again, I haven't taken the time to verify, but a quick scan suggests there are bands in each level where the graphic is formulaic enough that colour changes only happens in pairs of rows or more. It's certainly close enough that if not, and you wanted to save a few cycles it'd be trivial to make sure it actually did.


> colour changes only every few rows near the top of the screen. E.g. let those buildings (or whatever) extend to the top, but require the top floors to stick to the same colour. Now you can reduce e.g LDA/STA/LDA/STA/LDA/STA to LDA/STA/STA/STA and similarly reduce your inlined scroll code.

Here's the thing: I've just looked at video of Cobra. It's 100% plain to my eye (having worked on a multitude of published C64 games, over a number of years, and played a hundreds of C64 games, and taken their code apart to see how they tick) that this game is using full colour scrolling — albeit in only one direction. It might look like it's not, particularly on the first level, because you think the graphics look too simple. But sadly that's just how it looks.

You can plainly see this when various accent colours for e.g. windows and such like scroll into view. Don't be fooled by the fact it's tile based and the first level has poor graphics. And the fact it's full colour scrolling is even more obvious on later maps, e.g. see 5mins into this video:

https://www.youtube.com/watch?v=eog6-zvts6g

— That's full colour scrolling. In one direction. With tiles of 2x2 chars, with each char in the tile being able to have its own colour. 100%. There's no tricks there. Your theoretical/toy code example simply won't do what is seen on at the 5min mark there (level 2 or whatever).


> It might look like it's not, particularly on the first level, because you think the graphics look too simple. But sadly that's just how it looks.

I specificaly did not say that Cobra isn't using full colour scrolling. You're probably right that it is.

But what you've described does not require it.

I am saying that Cobra is an example of the style of level design that could easily get savings without sacrificing the graphics - including the accent colours. Cobra is otherwise simple enough that it probably wouldn't be worth it, but that is entirely besides the point I was making.

I did note the windows etc., yes. But the point is that there is no place in the whole game where there's a lot of big or different transitions going on at once, and the number of transitions is very small, and notably a lot of the transitions only occur at specific rows. The graphics as is is very constrained.

The 5m mark is a perfect example of exactly what I'm saying - only about ~11 rows changes colour, and from what I saw that's one of the most extreme transitions in the game. But while it affects many rows, it also uses few colours and so you can offset even some of that cost.

The way it's structured in faux 3D "layers" seems ripe to "decompress" the levels into a set of transition functions inspired by painters algorithm to "paint" bottom up, front to back, and then JSR at an offset into the transition function for the object "behind" if it extends past. You'd want to flatten some of the "layers" (at the cost of increasing the number of transition functions).

Here's what I'd try:

Since the transition functions can hardcode LDA immediate's, and STA absolute gets X indexing for one extra cycle, you can have the transition functions X index and used that to reuse the transition functions for every column. So e.g. instead of this:

   scroll_splat_colour:
      LDA #$00  # colour data for char
      STA $D800 # colour ram
      LDA #$00
      STA $D801
You'd get this for each transition sequence (could be a slice of an object, but in practice you'd probably want to flatten it somewhat, at the cost of more transition functions but reducing the cycle cost because of fewer JSR/RTS pairs):

    some_transition:
       LDA #$col1  
       STA $D800+offset_of_last_row_start, X
       STA $D800+offset_of_second_to_last_row_start,X
       ... and so on until colour change
       LDA #$col2
       .... sta to next row.
       RTS
You then decompress the level into a series of JSR calls per column, right to left + DEX, and a set of offsets. Every time you scroll, you then overwrite the DEX after the last (leftmost) transition with an RTS (and fix up the previous one), and JSR to the first (rightmost) list of bottom-up JSRs.

[Beware the likely errors in counting; long time since I've looked at cycle counts..]

You need to save 12 cycles per transition function for the JSR/RTS plus 2 for the DEX per column plus a handful of cycles to do the setup per frame to break even, plus 1 cycle per STA.

An LDA immediate/STA absolute pair is 6 cycles, so moving, say a 39x20 field adds up to 4680 cycles that way. If "everything" fails and you have one JSR + one DEX for 39 columns + STA absolute X-indexed for all 780 characters, you pay a cost of an extra 1287 cycles plus setup. Let's call it 1320. But this is before taking into account that you now don't need to do this:

    LDA scroll_splat_colour+6
    STA scroll_splat_colour+1
    LDA scroll_splat_colour+11
    STA scroll_splat_colour+6
Assuming you split that in 7 segments of 111 (for 780/7) updates of 4+4 cycles each, for 888 cycles, we're 432 short in the pathological case where every colour is different to the one below it and different to the one to its right.

But each STA absolute X-indexed we save, because colours do not change right to left, saves us 5 cycles. Each LDA we save because colours often repeat bottom to top saves us 2 cycles. If we assume these are evenly spread, we need 62 of each every frame to break even. In other words only 8% need to repeat. Of course if it just breaks even it's pointless.

The only constraint on the artist to do this would be to set a "budget" for transitions to make sure there's always enough repetition to make it worthwhile, but it's certainly doable.


The main issue here is that this doesn't really work for anything but horizontal scrolling. The code I explained works for all directions. One of the games I coded was an 8-way scroller. Another had horizontal sections seamlessly connected to diagonal sections.

Granted I didn't show different version of moving the data through the splat code, for different directions, I only showed a single direction. And I now realise that multi-direction was not mentioned in my OP. Which is most likely why we seem to be talking at odds with one another somewhat here.

The code I showed works for all of these cases (8-way, horizontal-diagonal transitions, pure horizontal or vertical) — sure, one needs extra variations on the actual scroll code, but not the splat code — plus it is easier to reason about, quicker to develop, and doesn't impose artificial constraints on the graphics/map/tile-usage — which means the graphics won't take as many iterations to get right (you can bet the artist will make mistakes in the map, 100% guaranteed — cos without also modifying the tooling to account for all of this, that's what artists always do. Speaking from experience!).

> The only constraint on the artist to do this would be to set a "budget" for transitions to make sure there's always enough repetition to make it worthwhile, but it's certainly doable.

Even for a single-way scroller, it's quite hard to tell if the benefits you claim here really outweigh all of the costs involved (not just CPU costs - but dev time, map design time, adjustments to tooling, etc). IDK if it'd get the go ahead in any of the places I've worked, without a fully working demo.

But yes, sure, your idea may well be more optimal at runtime, for single direction scrollers. But I don't see how it would / could work for all scroll directions. And the additional constraints would likely give the artists nightmares! ;)

And, as you say, worst case is still gonna be ~25% slower.

The biggest problem that one is trying to overcome here is the additional hit to CPU budget every n-frames (usually 8), when the color RAM update is needed. Having something that might, under certain conditions, be slower, could be problematic. Whereas having something that is constant time is, perhaps arguably, always going to be easier to deal with.

But thanks for taking the time to explain. I kinda thought that that's what you were implying.

Apologies I hadn't been clear that the code I showed (immediate load-stores) was a colour RAM splat technique that was applicable to scrolling in any direction. It's kind of a key point really, and I see I completely omitted it :/ I thought it was mentioned, but I now see that the 8-way scrolling conversation was a slightly different thread.


Sure, doing it for 8 way would require a different approach and would likely be a lot harder to make work (not impossible, but it would likely constrain level design quite a bit)

To be clear, the one you showed is a great baseline, and likely the best option for most cases unless you hit a wall where you absolutely need to save extra cycles.

Only then it'd be worth exploring something this much more complex.

I guess my main point is that if you hit that wall, then an approach specialised for the level design can give extra savings.

But of course you're probably absolutely right that it'd not fit the budget of a typical C64 game back in the day.

I'd also add that this is far easier to do today, so it's easy for me to propose as an alternative now, but it's unsurprising if nobody used it back then.

E.g. I could throw together a script to do near optimal arrangement (I'm pretty sure finding optimal arrangements reduces to bin packing, which is NP hard) of transition function to maximise the minimum saved cycles for any given level data on screen and run it fairly easily on my laptop, but the number of permutations of "flattening" of layers would have forced you to resort to educated guesses back in the day, and so your savings might be more marginal.

(But now I kinda wish I had the time to put together a working example and see how far it could be pushed)

In terms of the worst case, to be clear for this to be useful at all you'd need to verify it never hit it. Given how many random colour changes would be required to hit it, I think you could guarantee that simply with a few minor constraints on the tile set (e.g. every 2x2 tile on screen with the same colours in all four positions saves you 2xSTA's and 2xLDAs) coupled with a willingness to make small tweaks (e.g. deleting a window from an otherwise "busy" part of a level etc.).

You can relatively cheaply validate it, since calculating the cycles for any given screen contents is easy, so you could validate levels by "scrolling" through the whole thing and calculating a graph of cycle counts at any given point. Of course, this is again much easier to do today when we can hack up a trivial script to run through the level data in seconds than it would have been back in the day.

And of course as you point out, you'd have needed a very good reason to spend the extra time (and impose the extra limitations on the level design) to make such small savings, or you'd just not have been able to justify it.

So unless you had a game so complex you absolutely had no choice but finding ways of cutting it down, it'd have made no sense. Even then I'm guessing back then people would have made the static parts of the screen bigger instead of anything complex like this.


Sure. But arguably, that's a lot of extra work, plus some arbitrary restrictions (tiles of single colour, scroll directions), for a system that, at worst case, is surely going to be doing at least a little bit more work than the simple optimal colour splat technique I described.

Whereas if one has a system where there is no worst-case because/and it runs in constant time, and is as optimal as possible (i.e. the fastest way of updating all the necessary data) — which requires no restraints on the graphics, can work no matter which way the games/player scrolls, doesn't require much extra work on other frames (i.e. when not updating the colour RAM), nor any extra work using custom-made external tooling — it would, with little argument from most folk, clearly seem to be the better choice.

There are reasons why simple solutions often win out over more complex ones.

Particularly when coding on limited hardware. Particularly when under time pressure to publish. Particularly when graphics designer's iteration time has a cost per hour.

> So unless you had a game so complex you absolutely had no choice but finding ways of cutting it down, it'd have made no sense.

I've worked on lots of games projects that never actually got published, some of them were because we came across a wall, and despite trying lots of novel solutions, often many of which were 'outside the box', those issues couldn't be overcome. These things are massive time sinks, and, often, solutions that seem like good ideas, simply aren't.

Sometimes one simply has to accept that you cannot squeeze an elephant into a matchbox! It becomes easier to spot when solutions might not work as one becomes more experienced. But sometimes one might still spend time trying to squeeze the elephant.

Solving the worst case, with the least restrictions, in both the simplest and the most optimal way, often gives one a sensible measure as to what is actually reasonably possible.

— If you can reduce the time needed to do a full-colour update when scrolling arbitrarily (including 8-ways), with unrestricted use of colour design on the maps/tiles, on the C64 platform, then I'm sure there's a reasonable handful of folk that would like to hear your suggestions. Otherwise, technically you're solving another problem, and it's not the one which we were dealing with back then.


We absolutely agree it'd be a lot of extra work, hence I agree with you that it'd not have been applicable in most instances back then. Most of the time if you faced a squeeze like that you'd be more likely to agree to reduce the playing field by a row or two instead, or ditch something else. But being freed from those considerations and considering what is actually technically possible is what is interesting to me.

> — If you can reduce the time needed to do a full-colour update when scrolling arbitrarily (including 8-ways), with unrestricted use of colour design on the maps/tiles, on the C64 platform, then I'm sure there's a reasonable handful of folk that would like to hear your suggestions. Otherwise, technically you're solving another problem, and it's not the one which we were dealing with back then.

They are different problems, yes, but plenty of games have gameplay where 8-way scrolling is not what you're dealing with. And additional constraints also often fall out of the level design. To me it's the way those design constraints create opportunities to use additional tricks that are interesting, not the problems you were dealing with back then.

Frankly it's an extra artificial problem, because the state of the art of scrolling on the C64 today involves using "dirty tricks" from the demo-scene like VSP/HSP/AGSP which no "hardscroll" based approach like the ones we're discussing can compete with.


> I confess I was a bit amused when you wanted to give the graphics artist complete freedom.

That's because I'm speaking from a number of years of actual real-world experience working on all manner of released production games for the C64 (plus other platforms) — from arcade conversions, to film licenses, to cross-platform ports, to original projects — and in most of those situations, you simply don't get to call the shots.

It's hardly some unknown abnormal situation to allow the graphic artist to use the character colour. Loads of games had unrestricted use of colour RAM. It's just what you do in most cases, unless you have a monochrome game.

Your toy example here is all well and good, but is not a fully working system by any means — I don't see how it can generalise out at all. And it certainly doesn't seem to be a more optimal way to handle unrestricted scrolling, with a colour map, on the C64, which is what I was outlining the most optimal method of doing. Furthermore, it seems tangential to your originally mentioned idea.

Whereas the method I outline involves no restrictions, no overheads, and will handle 8-way scrolling — with full colour map. And it works 100%, and has been used in multiple published projects. It's not theoretical.

Do you have any actual examples of released games that used the technique which you describe? Or any articles you can point me at? Or perhaps a more detailed explanation of this technique and how it can be used across the whole screen (in whatever directions). I'm more than happy to take a look to try and see what I may have missed.

— Out of interest, have you ever coded any complete C64 games?

IDK, perhaps you're speaking about some trick used in demos/intros, in which fancy techniques often wouldn't generalise out into a full game.

Apologies if it seems that I am missing something that might be obvious to you. Clearly my work on a whole bunch of published C64 titles, and my years of programming the C64 commercially, in various teams with- or alongside- other experienced programmers, was some years ago now (I quit the game industry in the 90s), and clearly we must've overlooked the technique of which you speak of. Or dismissed it for some reason.


> Whereas the method I outline involves no restrictions, no overheads, and will handle 8-way scrolling — with full colour map. And it works 100%, and has been used in multiple published projects. It's not theoretical.

yes, it was wonderful enough to give the reader a clue how one would go about squeezing more and more performance out of that good old box. Nothing comes for free of course but there are pretty much infinite interesting trade offs to be had that usually exponentially blow up the complexity.

I mean you started out with a pretty easy to understand bit of memory transfer.

If the goal is to update "every visible char onscreen in scrolling area" it seems pretty much the final solution, nothing better is to be had.

Rephrasing the goal into "every changed char" is simply a different perspective. Most likely less productive but one could explore it as it would be faster if we restrict the freedom of graphics a bit.

Say you have a space ship <ooo> moving left to right by at most a single char. You have to set the chars that make up the ship and you have to insert a space next to it or it would turn into <<<<ooo> or <ooo>>>> There is no need to fill the entire line with spaces.

> perhaps you're speaking about some trick used in demos/intros, in which fancy techniques often wouldn't generalize out into a full game.

I never wrote games, I just tinker and rewrite bits of my demos producing inferior results 99 our of 100 times.

How many chars are we updating really if we change

  _ _<ooo>_ _ 
  1234567890A
into

  _ <ooo> _ _ 
  1234567890A
I think 3,4,7,8 but not 1,2,5,6,8,9,0,A ?

That was the train of thought in those days at least for me :)


Yeah, I get what you're saying. But it's somewhat of a moot point mostly, certainly when one looks at the bigger picture, but arguably perhaps even for the small picture.

Usually (for most games on C64), one simply assigns sprites for most moveable objects, and then one has a background scrolling in whatever directions. Many commercial games were generally produced within some restricted time frame, according to a publisher's date. So under that time constraint the whole game has to be built. Generally, setting up one's graphics / screen drawing code (sprite multiplexer and a scroll system, and a coordinate system to tie them together) is done right at the beginning, and is a tiny percentage of the total time one has allocated for the project. The bulk of the time is usually spent implementing the game itself. Most work on graphics tricks / optimisations is done outside of this, unless there is something the game specifically needs / depends upon — or unless one runs into performance issues.

Having generic re-usable code for one's graphics system — being able to flexibly handle lots of sprites, and scroll the screen in whatever directions are needed (the colour splat code I showed can be used for horizontal / vertical / diagonal / full 8-way scrolling, with the appropriate code to scroll the data through it) — even if that system as a whole might need a little customisation depending on the game — is a huge time saver, and almost a necessity.

Sure, as a toy example, for a single object, one can see there's not much in the way of changes when moving something like a paddle for breakout, when it is aligned to character boundaries. But writing a generic system for that, for multiple objects, on these lower powered systems, will likely see the technique fall on its arse - unless the game is mostly made from things with repeated characters, that move horizontally (or with otherwise limited movements and graphics). And even if that is applicable to the kind of game at hand, it's arguably still not a huge saving of cycles, so if one had already run into performance issues, one would likely be looking for cycle-savings that have bigger gains than that, i.e. bigger, lower-hanging fruit.

There's a lot to be said for simplicity, both at runtime and whilst coding / debugging / optimising.

Which is partly why having a generic and optimal colour-splat solution comes into the equation, because it was always a specific pain-point for C64 games, no matter which direction they scrolled. Having a generic solution means one simply doesn't have to worry about such tricks, and their various associated restrictions, the team can simply build games, using the system and its underlying h/w features. That solution also being as optimal as possible is a bonus, and usually comes after much time / many dev iterations, and the work of multiple bright minds. Hence me sharing the technique that Jon shared with me, back in the day.

Most C64 developers / dev teams back then had generic solutions for h/w sprite multiplexing and tile-based full-colour background scrolling (in whatever directions), and similar was needed on every other platform according to their given h/w, or lack thereof (e.g. Atari ST had no hardware sprites nor hardware scrolling, so one had a different bunch of problems to come up with generic solutions to). It was often pretty easy to swap out a scroll system or a sprite system for another on some given platform, to see if there were any real-world gains from changes in the implementation. Obviously, that possibility is reduced considerably the more one moves away from generic solutions, and into custom tricks, e.g. relying upon how the designer has used / has to use colour throughout the level, or the shape of moving objects, or which directions objects can move it.

Sorry if I come across as overly dismissive. Having spent so many hours on such things, over many years, with the input of multiple talented devs at the time, we've tried a lot of things to end up where we got to. We also came up with a million things that sound like nice ideas, but generally turn out not to be, due to overheads (hidden or otherwise) or other restrictions. That's not to say creative/novel solutions can't work or shouldn't be suggested. Just that often they've already been considered, and there are reasons they've not been used.

Your idea works fine — for things with both limited graphics (and/or colours, depending on where it is applied), and limited movement. But will likely have more overheads / take more cycles than one might imagine, if trying to turn it into a more generic system (for more objects, or for objects with less restricted graphics or movement).

It's not such a useful idea for background scrolling as one might initially think, because it either requires limiting the graphics (fine if you can do so: but these platforms had poor enough graphics, and gave graphics/map designers enough headaches, without additional restrictions), or having a bunch of code to calculate/track the changes.

Considering/proving the simplest case — here that's horizontal movement, over a horizontally aligned screen memory, for a single object — usually leaves a lot of issues unsolved. In general, and in most areas of coding.


How to handle the case when player changes direction to exact opposite immediately after the frame color data was transferred? Double buffering splatting code? Although one copy of it is 5001 bytes, ouch.


You generally don't handle that case! :) — Instead you let the player move within a rectangular area onscreen, and decide on which way you are going to scroll the screen in advance (or rather: after the fact, depending on how one looks at things), based upon where the player is inside that rectangle. So the screen catches up with where the player is moving/pushing.

Eight-way scrolling like this was always a massive pain on the C64 (and other systems that used buffered scrolling with no h/w, e.g. Atari ST), but that way (a box the player moved around inside) was the only realistic way of handling it if you had to do a bunch of work in advance before doing the actual scrolling. Turns out that having the player in a loose rectangle is also easier on the eye too, which is perhaps why it's also used on systems that don't suffer the same h/w restrictions.

Yeah, the colour RAM update was a lot of bytes to move. But dedicating a big chunk of code to it meant one could be a little freer to use slightly slower techniques elsewhere in the update cycle. Side note: the C64 actually only had 39 visible char across the screen when in 'scrolling' mode, because the borders where shrunk-in slightly (and slightly more than one expects). So one less char to worry about per line. That saved a tiny amount of code / memory / execution-time for the colour splat (and the scrolling of partial chunks - whether on back buffers, or the data within the colour splat code - over the other frames). Sure, it's only one less character. But it saved some cycles. And cycles mattered! Particularly when doing something with that much data to move / that took that much time.


> C64 actually only had 39 visible char across the screen

But 40 color cells were still visible, unless horizontal scroll register was 0.


No, but that's an easy enough mistake to make :) — It's called 38-column mode, and when enabled the VIC shrinks both borders in by 8 pixels, and then offsets the screen according to the x-scroll register bits.

[Edit: another source says it's actually 7-pixels hidden on the left, and 9 on the right. But whatever: same principle, the screen is shrunk by 16 pixels in total horizontally]

Which meant that at most only 39 characters were visible across the screen — with two of those, one at each end of the row, being partially visible — and that applies to both the character screen and its associated colour RAM. Only 38 characters were visible when the x scroll register was zero, and as soon as one shifted to a value of 1-7, the 39th column became visible (and the 1st one became partially offscreen). But the 40th column is never visible when in that mode.

For more info see:

http://www.devili.iki.fi/Computers/Commodore/C64/Programmers...

"When scrolling in the X direction, it is necessary to place the VIC-II chip into 38 column mode. This gives new data a place to scroll from. When scrolling LEFT, the new data should be placed on the right. When scrolling RIGHT the new data should be placed on the left. Please note that there are still 40 columns to screen memory, but only 38 are visible."

— But it's discussed on a handful of other pages too, if you google.


Oh damn... and I did a fair bit of coding on C64 back in the day. :-D

Somehow I thought it hid 4 pixels both sides. Totally wrong.

PS. Then it's so unfair bad line still takes 40 cycles!


Please stop giving the above comment downvotes because of this person's lack of knowledge: we all have to learn things — there was once a time I didn't know this either.

It's not like vardump here was being a dick about anything in their comment, cut them some slack!


Thanks. Although I really should have known better, wrote scrolling routines 35 years ago.

It's scary time can corrupt memories we consider as facts.


I made an 8-way full-screen scroller.

To avoid situations like this the player sprite at the center of the screen had momentum, i.e. the sprite had to rotate 180 degrees to change to the opposite direction, giving a few frames time to set everything up.


That's a nice little trick, cheers for sharing. (Not that I'll get a chance to use it these days, but still)


That's... that's horrible. Beautiful, but horrible.

Which kinda describes any advanced c64 technique, really.


Indeed, I totally agree on all points :)




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: