Jump to content
IGNORED

A Two-Player Competitive and Co-Op "Tetris" for the Atari 2600 VCS


AkashicRecord

Recommended Posts

 

It appears that the Internet Tetris Gods (see YouTube video above) have once again graced me with their benevolent presence; this time in the form of lost source code:

 

 

Searching the Internet Wayback Machine for one of my old expired domains revealed a strange little Easter Egg from exactly this day, October 13th, almost 20 years ago... Somehow I let a code listing slip through just long enough for it to be archived. Damn.

 

https://web.archive.org/web/19991013125024/http://pknet.com:80/xtrix/HTML/S/main.C.html

Nothing ever truly gets deleted. Tis the nature of the cloud...

 

Sorrry about your hard drive crashes. I've still got stuff I downloaded / created 20 years ago backed up, most of it is crap though.

Link to comment
Share on other sites

I'm attaching individual image mockups of the seven game pieces to work from. The sprite data should be pathetically simple for these. There are a total of 19 orientations that need to be accounted for. There are some constraints regarding positioning depending on the piece and it's current rotation...for instance, a Line piece rotated flat can only move left or right 6 ways, when it is rotated vertically, it can assume 10 different horizontal locations.

 

As for the drawing and positioning, it is probably best to precalculate everything in tables, indexed by the piece's current position. Horizontal movement and positioning will require delays of a certain number of CPU cycles; we should only need a granularity of about 12 TIA color clocks to hit each position for our game grid as it translates to the screen (easier said than done). For vertical positioning, we just need to skip a few scanlines...

 

 

post-66218-0-08691500-1539534956.pngpost-66218-0-20545200-1539534963.pngpost-66218-0-50567300-1539534969.png

post-66218-0-36811800-1539534975.pngpost-66218-0-75556500-1539534984.pngpost-66218-0-60202800-1539534988.png

post-66218-0-23977700-1539534994.png

  • Like 2
Link to comment
Share on other sites

I spent a few hours experimenting with various settings of the NUSIZ0 register, and it does indeed look like most pieces will be covered by just modifying a single bit in that register, as I expected; the sprite data is hardly required to change (and this is a good thing.)

 

A lot of pieces can also be drawn by smearing quad and octuple-sized missiles over a few scanlines. The "T" "L" and "J" blocks (when rotated flat) need to cover 12 pixels across, so this can be accomplished by setting 3 bits of a quad-sized sprite, or 6 bits of a double-sized sprite...another option is a full 8-bit single-sized sprite with a quad-sized missile, but that might be overdoing it a bit... the "T" block is probably going to be the most finicky piece to render.

 

Here is the output of a naive drawing routine with hardcoded positioning to get an idea of how the flat Line piece might look on screen. I've simplified the playfield for testing...

 

post-66218-0-39338300-1539550332.png

 

...and here's something close to the square piece on the 2P side of the field:

 

post-66218-0-27266100-1539551374.png

Edited by AkashicRecord
Link to comment
Share on other sites

....there may be a way for me to kind of "cheat" at drawing some of the game pieces...

 

In an effort to minimize data and updates, and thus CPU, I could simply set sprite colors to BLACK (while still leaving them ON) and drawing the playfield with priority over the sprites. This could allow me to set the coarse and fine sprite position very early (once per frame) and simply set and decrement the color gradient on the appropriate scanlines. On the scanlines below the piece, set the sprite color to black and ignore everything until next frame, and rinse / repeat. Plus, once the color is set to black, it will stay that way until I change it on the next frame.

Edited by AkashicRecord
Link to comment
Share on other sites

And here's a quick example of what I was briefly mentioning. This is the same image of the Square block being rendered, but with it's sprite color being changed to BLACK on the remaining scanlines, while also enabling DEBUG colors in Stella. Setting the playfield priority eliminates a little black "hole" on the floor where the piece would be drawn in black over the playfield floor at the bottom. You can easily see the "striping" of the sprite going down the screen, but this is not visible:

 

post-66218-0-56080200-1539555459_thumb.png

Link to comment
Share on other sites

I made an error (on the good side, thankfully) in my previous calculations of RAM usage for the playfield, especially for two players. Luckily, I overestimated the RAM usage by double! Which leads me to my next concern:

 

My more advanced plans for kernel design is to use some "self-mogrifying" code executed directly from RAM. This means that I would be dynamically rewriting operands and opcodes in memory prior to their execution. I'm not going to start here however. My next actual concern must be the playfield bitmap, since this is essentially what is going to drive my kernel (especially in regard to horizontal and vertical positioning) based on scanline and frame numbers...

Edited by AkashicRecord
Link to comment
Share on other sites

Earlier, I had an idea regarding the game's 10x20 playfield bitmap (times two, for 2P.) Since I overestimated the RAM usage by a decent amount, I may be able to use 2 bytes per "line", for a total of 40 bytes for a single player. This is obviously 80 bytes for two players, and I need at least a few variables for the nice things...but all is not lost. I may have to ditch my self-mogrifying kernel idea, but at the same time I will be gaining 6 bits on each "line" of the 10x20 field that I can potentially use as some sort of "status" flag which I can test on a line-by-line basis (again, this is the game's "lines," NOT scanlines that I'm referring to.) By doing so, I could drive some of the kernel's decision-making logic by using these extra bits to signal specific sprite-drawing scenarios or strategies...such as when the 1P and 2P sprites "overlap" on some scanlines, as this drastically changes the kernel logic when both player sprites need to change.

Link to comment
Share on other sites

As for music (if I have the ROM and CPU for it) I was thinking of either writing my own music, or at least borrowing from one of the greats:

 

 

...it's certainly not possible for any sort of full rendition of Rachmaninoff; Hell, it's impossible for most people to even physically play his music... :D

 

 

That said, I've done game music in the past, since I'm also (unofficially, and not commercially) a DJ and electronic music composer. My past projects however, afforded me much more freedom, although this is most certainly off-topic:

 

 

Edited by AkashicRecord
  • Like 2
Link to comment
Share on other sites

I'm taking a quick JuMP over to timers, timing, and frame counting.

 

I threw together a boring .bin which cycles the playfield color every few frames. The reason for this silly test is that frame-level timing like this is what will essentially determine the game's maximum difficulty as far as how fast a player's piece will advance at later stages. This is also where I need to look at the granularity of input polling, and so on. This has a huge effect on how the game will play and feel, so it has to be perfect...some things will probably benefit from use of the built-in timers.

 

Later I'll have a look at converting the color cycling into a sprite drawing routine that will draw the sprite on specific scanlines, incrementing every so many frames, simulating the game's piece advancement.

Edited by AkashicRecord
Link to comment
Share on other sites

So now I have to make a fairly large decision as to how smooth the game's animation will be. For now I'm mostly referring to the vertical animation.

 

Since the game field has 20 vertical positions, this breaks down into small chunks of scanlines per game field location. I'll call the vertical field position as Y, and this will be convenient since I'll generally be using the Y register as a scanline counter. I'll have the option of drawing the games pieces and inching them down the screen "in-between the grid" so to speak. This would give a much smoother and more fluid animation. The more basic and naive approach would have each piece drawn in only their fixed grid locations, but this might be considered "jerky" animation...

 

Applying this to horizontal positioning (in between the grid, again) would have some impact on ROM size since I'll have to use more coarse and fine position table data.

 

One other thing about the game's playfield is that I may want to literally turn it upside-down (or at least think about it upside-down) because this type of code shaping will make good sense given the idiomatic decrement-and-branch nature of assembly.

If I approach my game logic in the same fashion, then everything will translate into code without much issue. Remember, when we decrement a value, we get a "free" comparison against zero that we can always use.

Link to comment
Share on other sites

While working out the game's playfield I realized that one of my 2P game modes will be easiest to implement, and should be the first place to start.

 

This mode has 2P with separate game fields, but the fields are replicated...both players contribute to clearing a shared field, but on separate sides. Piece-swapping in this mode is also shared, but that's going too far right now. ;)

 

What makes this mode easy to code is because the VCS playfield works exactly in the way I need it to work in order to implement this functionality.

Link to comment
Share on other sites

Here's the first .bin I can share...it doesn't do much, but it sort of illustrates the fine motion of moving something 1 scanline each frame. After some number of frames the scanline with which to start (and stop) drawing is reset back to a starting point, and the playfield color is decremented.

As for the sprite drawing, this example is really just setting the color to NOT black. Actually, this isn't *entirely* true, because there is a bug, and I am still resetting the sprite position even though I don't need to. As I mentioned in an earlier post, if I am going to just reset the sprite color, then I can reset its horizontal position *much* earlier (like at the start of the frame during VBLANK) and forget about it until the next frame...if it moved.

new-draw-test.bin

Not sure if this will execute on real hardware...

Edited by AkashicRecord
  • Like 2
Link to comment
Share on other sites

made a few minor changes to the first .bin to illustrate the more "jerky" animation method that I was talking about. After looking at this for a few minutes, it doesn't actually seem too bad to me... Tell me what you think! (The graphics are still in "super simple mode" to keep things simple at first.)

 

new-anim-test.bin

Edited by AkashicRecord
Link to comment
Share on other sites

Since there wasn't much to change to add the small gradient graphics effect that I plan to use in most cases for the game pieces (when possible), here it is applied to the previous animation test, and the piece is nudged over to the 2P side of the screen just for the heck of it:

 

new-anim-test3.bin

Edited by AkashicRecord
Link to comment
Share on other sites

My next drawing test is going to be a bit different, I'm going to investigate "inverting" the VCS playfield and background and use black playfield blocks to draw over solid sprites (such as the "T" block) to sort of "obscure" areas of the pieces so that I can further simplify my drawing strategies. Combining a few of these techniques might let me squeeze a lot of nice detail out of things without overshooting the beam.

Edited by AkashicRecord
Link to comment
Share on other sites

I'm taking a quick break from animation tests and going back over to the actual sprite bitmaps, and how they are going to be sized and translated on to the screen via the NUSIZx registers. As I mentioned, I wanted the sprite data to be as simple as possible, and reused as much as possible, and today I quickly realized how easy this is. I don't really even need to use more than 1, 2, 3 or 4 pixels...and this isn't even using missiles...that's just icing on an already tasty cake.

 

This is in no way how the game would actually look, because I don't have any double-piece drop options...yet...but check out the "fake" sprite replication effect by essentially doubling up on the sprite data: I can replicate this 3 times for both player sprites and get a lot of action on the screen...12 pieces? (I'm seeing how this could lead to an actual Dr. Atario game in the future...though the simultaneous colors for that one is still not an easy task without some more wizardry.)

 

post-66218-0-75442800-1539787577.png

This doesn't even have horizontal positioning in effect, and the result is almost correct...

Link to comment
Share on other sites

This is a little off-topic, but it came up the other day as I was writing some of this code.

Completely out-of-the blue, Atari's current CEO appears on a television segment in the background talking about stocks and the upcoming console:

https://www.youtube.com/watch?v=l2xifMcu-8o

Is it just me, or does he seem really confident in the performance of his "Atari Sheers" :rolling:

fiskars-hedge-shears-391690-64_1000.jpgn

 

This should probably go in the Ataribox thread btw...

  • Like 1
Link to comment
Share on other sites

Is it just me, or does he seem really confident in the performance of his "Atari Sheers" :rolling:

 

This should probably go in the Ataribox thread btw...

That was the thread I was looking for :)

 

It looks like the video got its own thread recently, which is even better.

 

I hope the system does well and finds its niche. Everyone I've mentioned it to has had positive opinions, and thinks it's an interesting idea.

 

 

We now return to your regularly scheduled Tetris programming...

Edited by AkashicRecord
  • Like 1
Link to comment
Share on other sites

I don't know if you have been thinking of NTSC/PAL compatibility, but it might be good to implement that now instead of later. All you really need to change between the two is the length of vblank and overscan, plus the speed of the game. Without adjusting for speed, PAL games run at 5/6 speed, which is very noticeably different. Since you've been working on game speed, I thought I would suggest it.

I haven't implemented speed into my NyanCat project yet, but I plan on using the typical method of having an 8-bit "fractional" counter that changes your object's position when the counter rolls over. This way, you could add values that are multiples of 5 in NTSC mode, and multiples of 6 in PAL mode, and both modes would play at exactly the same speed.

Edited by JeremiahK
  • Like 2
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...