Jump to content
IGNORED

A few questions before I attempt to code anything


tokumaru

Recommended Posts

Hello everyone. I'm new here but I've been lurking around for a while now.

 

I've been studying this little beast that is the 2600 through Andrew's lessons and a few other docs. I'm finding it all very interesting, and will probably try to code something for it soon.

 

I'm not a newbie when it comes to game coding, I'm an experienced NES programmer (who has nothing great to show yet, unfortunately), but since the 2600 had a part in my childhood I recently developed some interest in programming it also.

 

Since I'm used to coding for the NES, 6502 asm is like a native language to me, and I often find myself coding stuff in my head during the day, so that's taken care of. I'm focusing on the TIA right now, and I believe I understand most of it's workings by now, but I do have a few questions about the 2600 that I'd like you guys to answer for me.

 

1. Since you have control of the number of scanlines the game outputs (should be 262) and you have to control that very carefully, how exactly do you handle the game logic? I mean, when the picture is rendering the program has to pay 100% attention to the TIA, to update everything at the right times. So, the time to handle game logic would be during VBLANK and in the OVERSCAN area. However, since those regions must have a constant number of scanlines, does that mean your game logic has to be constant-timed also? That'd be very weird, since there are a lot of conditional stuff in the game logic, which would make it nearly impossible to have it use the same ammount of cycles every time. So, how do you handle game logic and timing during VBLANK and OVERSCAN?

 

2. About player positioning, I think I understand the code to do that (the "revolutinary" one), although it took me a while to find out that it takes 5 pixels for RESPx to take effect, and that made everything seem a little off for a while. Anyway, I'd like to know if it's possible to place the players before the left edge of the screen, before TIA cycle 68, so that they can smoothly enter the screen.

 

3. Another one about player positioning: At first, I though that HMPx was only used to graphically displace the players from the location where RESPx took place, but it seems that it actually moves them. Does that mean that if my game is a simple one, where each object only moves a couple of pixels to the left or to the right (and are not reused anywhere else in the screen), I can get away without having to use the RESPx magic? Could I just use the first few frames of the game to position all the objects to the far left and gradually move them to their starting positions and take it from there? I know this is not very "professional", but could be used for simpler games, right?

 

I guess this is all for now, thanks for the help!

Link to comment
Share on other sites

Welcome!

 

So, how do you handle game logic and timing during VBLANK and OVERSCAN?

 

You can set timers for that. You just do all your stuff, then wait until they expire. Try looking up registers INTIM and TIM64T for the start.

 

Anyway, I'd like to know if it's possible to place the players before the left edge of the screen, before TIA cycle 68, so that they can smoothly enter the screen.

 

That is not possible, since sprites just wrap around. To resolve that, you can either buffer sprite data in RAM, prepare preshifted ROM shapes or, most commonly, you just move the sprite either under the left side HMOVE lines or under a black playfield column set to higher priority.

 

Does that mean that if my game is a simple one, where each object only moves a couple of pixels to the left or to the right (and are not reused anywhere else in the screen), I can get away without having to use the RESPx magic?

 

Yes, some games indeed do that. It will only work if you don't need to know the position for software collision detection or else though.

Link to comment
Share on other sites

So, how do you handle game logic and timing during VBLANK and OVERSCAN?
You can set timers for that. You just do all your stuff, then wait until they expire. Try looking up registers INTIM and TIM64T for the start.

Yup...there's plenty of examples to draw from. Just be sure to set your timer high enough for "worst case" using one of the TIMxxx's, do your game logic routines, then use an empty loop that waits until INTIM reaches zero to begin a new display.

Link to comment
Share on other sites

Welcome!

Thanks!

 

You can set timers for that. You just do all your stuff, then wait until they expire. Try looking up registers INTIM and TIM64T for the start.
Yup...there's plenty of examples to draw from. Just be sure to set your timer high enough for "worst case" using one of the TIMxxx's, do your game logic routines, then use an empty loop that waits until INTIM reaches zero to begin a new display.

That makes a lot of sense guys, thanks. I was wondering if there was't some sort of IRQ for that, but I see you are supposed to poll this "INTIM". I don't know if this is better than an IRQ, since with those you'd never miss the exact spot... then again, what good is it to know when to draw the frame if you haven't yet finished calculating all the information for it? I'll be very careful with that.

 

That is not possible, since sprites just wrap around.

Ah, I didn't know they wrapped around (should have payed more attention to the games, that probably happens once in a while)! So, the sprite will appear incomplete on the left, if I place it at positions > (160 - SpriteWidth)? Of course, it'll still have part of it on the right side, but the left side will look as I first asked?

 

To resolve that, you can either buffer sprite data in RAM, prepare preshifted ROM shapes or, most commonly, you just move the sprite either under the left side HMOVE lines or under a black playfield column set to higher priority.

I see... you have to do it in software then. HMOVE lines are those black lines on the left? I didn't know those were caused by HMOVE. I wish there was a way to avoid that.

 

Yes, some games indeed do that. It will only work if you don't need to know the position for software collision detection or else though.

Oh yeah, you won't have any records of their positions... unless you update some variables by the same ammounts you move the sprites.

 

Thank you very much for the replies, guys. Sometimes there are those tiny bits of information you can't seem to find when searching through the docs. I hope I'll enjoy this system as much as I enjoy the NES!

 

Thing is that my favorite game style is kinda hard to do on the 2600: multi-scroller platformers. Maybe a side-scroller is possible though...

Link to comment
Share on other sites

That makes a lot of sense guys, thanks. I was wondering if there was't some sort of IRQ for that, but I see you are supposed to poll this "INTIM". I don't know if this is better than an IRQ, since with those you'd never miss the exact spot... then again, what good is it to know when to draw the frame if you haven't yet finished calculating all the information for it? I'll be very careful with that.

 

An IRQ would be better, but the 6507 doesn't have interrupts (well, it has the BRK "software interrupt" instruction, but no IRQ or NMI lines). As long as the longest path through your game logic takes less time than the timer is set for, you'll be fine. The really difficult timing stuff is in the kernel :)

 

Thing is that my favorite game style is kinda hard to do on the 2600: multi-scroller platformers. Maybe a side-scroller is possible though...

 

A side-scroller would be kind of ugly, since the playfield pixels are really wide and flat. There are only 40 of them on a scanline, and there's no way to fine-scroll them, so the playfield would jump when it scrolls. It can look OK for simple playfields... see Defender for an example.

 

Vertical scrollers can scroll one scanline at a time, so they can be a lot smoother... see River Raid for an example.

Link to comment
Share on other sites

A side-scroller would be kind of ugly, since the playfield pixels are really wide and flat. There are only 40 of them on a scanline, and there's no way to fine-scroll them, so the playfield would jump when it scrolls.

Not necessarily. There is a type of scrolling usually done in systems with no hardware scrolling (such as the MSX or the CPC, that seemed to use this once in a while) in which you scroll the screen a somewhat big ammount at once (a tile per frame, or a pixel per frame on the 2600), when the player approaches the edge of the screen. Since it moves in blocks, it just looks as if the camera was quickly moving to show the player what he's about to face... it looks good, in my opinion.

 

I guess the real problem in side-scrolling on the 2600 is the lack of RAM, rather than the video hardware. If there was enough memory to buffer the rows of pixels, they could be rotated every frame with the new data comming in. But then maybe there would not be enough time to rotate them all and still perform the game logic.

 

I'll tell ya, this way of rendering a screen with full attention of the software to manipulate each small entity that composes the screen every scanline is pretty unique...! It has it's advantages, as this allows you to render a completely different image every time, but because there is so little RAM, most things have to be calculated on the fly (which allows for very limited complexity) or copied directly from ROM (wastes ROM space, and there is no way to pre-calculate every possibility), as there is no way to buffer things.

 

Vertical scrollers can scroll one scanline at a time, so they can be a lot smoother... see River Raid for an example.

Yeah, no problem for the 2600 there.

Link to comment
Share on other sites

1. Since you have control of the number of scanlines the game outputs (should be 262) and you have to control that very carefully, how exactly do you handle the game logic? I mean, when the picture is rendering the program has to pay 100% attention to the TIA, to update everything at the right times. So, the time to handle game logic would be during VBLANK and in the OVERSCAN area. However, since those regions must have a constant number of scanlines, does that mean your game logic has to be constant-timed also? That'd be very weird, since there are a lot of conditional stuff in the game logic, which would make it nearly impossible to have it use the same ammount of cycles every time. So, how do you handle game logic and timing during VBLANK and OVERSCAN?

 

This was the issue that caused my 10+ year hiatus in 2600 programming. I managed the Strat-O-Gems kernel in 1994 (though it went by the horrible name of "Colorms") but gave up on trying to divide the game logic into snippits of 73 cycles or less and count how many such snippets were being executed.

 

One trick not yet mentioned is to set TIM64T to a value of ~124 plus the required delay, and then wait for it to count down to 124. While this may in many cases seem silly, it can be very useful if your game will have "thinks" which may take too long to finish in one frame. In Strat-O-Gems, there are many places with code like this:

VLoop:
			bit	 INTIM
			bmi	 VNoKernel
			jsr	 KERNEL_V
VNoKernel:

Provided the loop never takes more than ~200 cycles or so per iteration, I don't need to worry about exactly how long it will take. The above code will add 7 cycles per iteration of the loop, but it frees me from having to worry about how much time the various loops will take. To ensure that the game runs at a uniform rate, I have a "down counter" which I decrement each frame unless it's zero. When a gem hits the bottom, I load this counter with a certain value, then do all my calculations, and then call the kernel until the counter hits zero.

 

2. About player positioning, I think I understand the code to do that (the "revolutinary" one), although it took me a while to find out that it takes 5 pixels for RESPx to take effect, and that made everything seem a little off for a while. Anyway, I'd like to know if it's possible to place the players before the left edge of the screen, before TIA cycle 68, so that they can smoothly enter the screen.

 

Another technique not yet mentioned for showing a sprite only at the left edge or only at the right edge of the screen is to write GRPx twice per line. To show the object entering on the left, e.g., set GRPx to the object shape during horizontal blank, and then sometime during the display set it to zero.

 

3. Another one about player positioning: At first, I though that HMPx was only used to graphically displace the players from the location where RESPx took place, but it seems that it actually moves them. Does that mean that if my game is a simple one, where each object only moves a couple of pixels to the left or to the right (and are not reused anywhere else in the screen), I can get away without having to use the RESPx magic? Could I just use the first few frames of the game to position all the objects to the far left and gradually move them to their starting positions and take it from there? I know this is not very "professional", but could be used for simpler games, right?

 

Combat does precisely that. It even uses the "lock missiles to players" hardware to position the missiles when the player fires, since the game has no idea where the players are located.

 

Stella Doomsday Interceptor (a 1K version of a missile defense game) tracks the position of the player's cursor (the Ball) but only repositions it by using HMBL/HMOVE to nudge it +/- one pixel per frame. A curious side-effect of this is that pushing left and right simultaneously will cause the position to be incremented and decremented (thus having no effect) but will load HMBL with $F0, causing the Ball to move right once per frame, getting out of sync with the expected position. Disciplined code should avoid such bugs, but when trying to fit everything into 1K, something's gotta give).

Link to comment
Share on other sites

That makes a lot of sense guys, thanks. I was wondering if there was't some sort of IRQ for that, but I see you are supposed to poll this "INTIM". I don't know if this is better than an IRQ, since with those you'd never miss the exact spot... then again, what good is it to know when to draw the frame if you haven't yet finished calculating all the information for it? I'll be very careful with that.

 

An IRQ would have been handy for some games like Strat-O-Gems. The polling code I had to stick in the middle of many loops wasn't totally horrible, but coding would have been a lot more convenient if I hadn't had to worry about it.

 

I see... you have to do it in software then. HMOVE lines are those black lines on the left? I didn't know those were caused by HMOVE. I wish there was a way to avoid that.

 

There is; I'm not sure when it was first discovered.

 

Unlike many systems which use a register to hold the desired horizontal position of each object, and then trigger a sprite when the raster position matches the programmed value, the Atari 2600 has a counter for each sprite that counts 160 pulses and then wraps. The sprite is triggered when the counter wraps, and in the case of players or missiles may also be triggered 112, 128, or 96 beforehand. The counter normally advances once on each displayed pixel, and does not advance during horizontal blanking. Since there are 160 displayed pixels per line, if the counter wraps 2/3 of the way through one scan line, it will wrap again 2/3 of the way through the next scan line, etc. Hitting RESPxx will zero the counter, causing the sprite to appear on future scan lines below the present position.

 

The HMOVE circuitry moves sprites in two ways:

 

-1- It adds feeds the counters extra pulses (generally 0 to 15 of them) during the horizontal blanking time; each extra pulse will move the sprite one pixel left.

 

-2- It blanks 8 pixels on the next scan line, disabling the motion clocks during that time. This will move all sprites eight pixels to the right.

 

An HMxx value of zero will cause the pulser to output eight pulses when triggered. Values of $80, $F0, $10, and $70 will output zero, seven, nine, or fifteen pulses respectively.

 

Writing to HMOVE on cycles 0-2 (e.g. performing an HMOVE immediately after a WSYNC) will trigger both of the above effects; any pulses generated will occur during horizontal blank. Writing to HMOVE at cycle 74 (i.e. performing an STA HMOVE which begins on cycle 72) will trigger the first effect, but not the second. This will cause all sprites to move eight pixels to the left of where they would with a normal HMOVE, but without causing any nasty black bars. Note that it is not possible to move sprites rightward with this approach, and the HMxx registers must be set to $80 for any sprites you don't want moved.

 

Writing to HMOVE at any other time is generally not recommended, since different 2600's will behave differently if the pulser is running during the displayed portion of a scan line. Note that performing an HMOVE or changing an HMxx register while the pulser is already running may have interesting effects which, to my knowledge, are not simulated correctly by any current released emulator.

Link to comment
Share on other sites

A side-scroller would be kind of ugly, since the playfield pixels are really wide and flat. There are only 40 of them on a scanline, and there's no way to fine-scroll them, so the playfield would jump when it scrolls.

It doesn't have to be like that.

 

As long as you scroll fast enough (>=~20Hz), it doesn't look ugly at all. So either you create an always fast scrolling game or you use "delayed scrolling" like I did in Thrust.

Link to comment
Share on other sites

Thanks for the info, supercat.

 

About Thrust, that's exactly the kind of scrolling I was talking about. It doesn't look bad at all. However, this only seems possible in this game because the playfield graphics are very simple: only lines of a single color, spaced by a few blank scanlines where the needed calculations can be performed. Still very cool, of course.

 

Since we're talking about playfields, let me ask one more question: how practical is it to use asymmetrical playfields in a game? I mean, if you spend most of the scanline time updating the playfield patterns, there will be no time at all to change the sprite patterns, change colors and so on. It doesn't seem possible to have asymmetrical playfields in an actual game, but I'm sure it has been done before, so what am I missing here?

 

Thanks again for all the help, you guys at the AtariAge forums are very nice people!

Link to comment
Share on other sites

Depends what you mean by "8-way" and if you're including unfinished games :?

 

With "8-way" I mean all 8 directions you can go with a joystick. U/D/L/R plus the diagonals.

 

And I was only considering finished games, in case you're thinking I forgot about your Rally-B and Superbug WIPs ;)

Link to comment
Share on other sites

Since we're talking about playfields, let me ask one more question: how practical is it to use asymmetrical playfields in a game? I mean, if you spend most of the scanline time updating the playfield patterns, there will be no time at all to change the sprite patterns, change colors and so on. It doesn't seem possible to have asymmetrical playfields in an actual game, but I'm sure it has been done before, so what am I missing here?

 

Nothing actually. You nailed it.

 

A 2600 kernel is always a compromise. The more cycles you invest into the playfield, the less are remaining for colors and sprites and vice-versa.

Link to comment
Share on other sites

Since we're talking about playfields, let me ask one more question: how practical is it to use asymmetrical playfields in a game? I mean, if you spend most of the scanline time updating the playfield patterns, there will be no time at all to change the sprite patterns, change colors and so on. It doesn't seem possible to have asymmetrical playfields in an actual game, but I'm sure it has been done before, so what am I missing here?

It is possible, but you have to make compromises.

 

Either you use a striped playfield (like e.g. Thrust, Crazy Balloon, Dig Dug etc.), or you only use PF1 and PF2 (like e.g. the PoP demos), or you use none or only a very simply coded sprites during playfield display.

Link to comment
Share on other sites

Nothing actually. You nailed it.

I see... I guess you only use them (asymmetrical playfields I mean) in sections with little to no sprite action.

 

A 2600 kernel is always a compromise. The more cycles you invest into the playfield, the less are remaining for colors and sprites and vice-versa.

Yeah, everything has to be very well planned, so that different sections of the frame can have different effects that do not interfere with each other. I'll eventually get the hang of it.

 

All this freedom the 2600 gives to programmers can be both a blessing and a curse! I guess this is what makes this system so fun!

 

Now that I think of it, I guess I could have simpler methods to fake an asymmetrical playfield (by not letting the player notice that it actually is symmetrical), by changing the color of the playfield to the same one as the background halfway through the scanline to hide an object that already appeared on the left side, for example. That sounds doable, as long as it's well timed. The right side will have to look empty, but at least it will not look identical to the left side. Also the effect can be inverted, so that sometimes objects are on the right only.

Link to comment
Share on other sites

Now that I think of it, I guess I could have simpler methods to fake an asymmetrical playfield (by not letting the player notice that it actually is symmetrical), by changing the color of the playfield to the same one as the background halfway through the scanline to hide an object that already appeared on the left side, for example. That sounds doable, as long as it's well timed. The right side will have to look empty, but at least it will not look identical to the left side. Also the effect can be inverted, so that sometimes objects are on the right only.

Sure, but this is less flexible and it also requires two TIA writes. So you hardly would save any CPU time here.

 

And it doesn't let you use hardware collision detection anymore.

Edited by Thomas Jentzsch
Link to comment
Share on other sites

Sure, but this is less flexible and it also requires two TIA writes.

Two writes? You mean one to hide the right side and another one to show the left side of the next scanline correctly, right?

 

And it doesn't let you use hardware collision detection anymore.

Yeah, I figured that. I am used to performing collision detection in software, as none of the other systems I coded for had reliable hardware detection. But I bet this feature can save you a lot of time on the 2600.

 

I liked the idea of not using all 3 playfield registers, maybe only one of them. That would allow for some playfield contents and I could still rely on the hardware collision detection.

Link to comment
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...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...