Jump to content
  • entries
    16
  • comments
    181
  • views
    35,539

Some progress on Space Invaders 7800


PacManPlus

3,092 views

Finally got to work on this a little this past week, and I made a little progress, and ran into some stumbling blocks. There are some screenshots below :) As of right now, my biggest issues with this are:

 

1) How to do the shields, and have them 'break away' piece by piece. I am assuming they have to be sprites(like the ufo and player) instead of cells from a character set (like the invaders), but I haven't a clue how to start it.

 

2) The left and right edges. Being that the screen is being manipulated to give the illusion of the invaders 'marching', I'm wondering how I'm going to know when a left-most or right-most column of invaders are completely cleared. I need to know this because any time an outermost column is cleared, the remaining invaders now march to that edge. So the edge boundaries need to be moved, in effect. hmmm.... Keep an 11 member array of the invaders, (think of the invaders on their side), and when the first or last members equal zero I'll know an entire column has been destroyed... maybe...

 

blogentry-1787-1206887400_thumb.pngblogentry-1787-1206887405_thumb.pngblogentry-1787-1206887409_thumb.png

 

04/14/08:

blogentry-1787-1208225785_thumb.png

 

06/13/08:

blogentry-1787-1213364189_thumb.png

61 Comments


Recommended Comments



(1) They probably could be characters or sprites but the data will probably need to be in RAM. I am guessing sprites would be best since I don't think having them be characters buys you anything. Unfortunately due to the layout of data for either that probably needs a 2K block (although you can use any unused sprite areas for other things).

Link to comment
(1) They probably could be characters or sprites but the data will probably need to be in RAM. I am guessing sprites would be best since I don't think having them be characters buys you anything. Unfortunately due to the layout of data for either that probably needs a 2K block (although you can use any unused sprite areas for other things).

 

You could use smaller zones for the sheild. That would increase the space required by display lists, and using smaller zones there than elsewhere on the screen could complicate the code, but going with 4-line display lists would cut the RAM requirement to 1K. As to whether that's worthwhile, I'm not sure.

 

I would suggest that for maximum arcade-y goodness, you should probably use separate sprites for the eleven invaders on a line. The arcade doesn't march all the sprites simultaneously; there is a noticeable 'ripple' as the aliens move. I would suggest that you should try to mimic that by moving the aliens at different times.

Link to comment

I actually was thinking a Sprite for the shields as well. I was more thinking of how to do the 'break-away' part when the bomb (or player's shot) hits it...

 

I know what you guys are talking about with regard to he 'ripple effect'. That was bugging me because it was always in the back of my mind that I had to do that. Now that you brought it out into the open ( :lust: ) I have to figure it out. I'd like to change he invaders to sprites. Do you think manipulating 55 sprites (+player +ufo +4 shields) per frame will be too much for Maria?

 

That said, it's kind of on hold for now. I'll have to get back to it again :cool:

Link to comment

Now.....

 

I think I have the 'ripple' matched like the arcade does. The only thing that bothers me, is that at their fastest march (when there's only one left), they aren't as fast as the arcade game. :roll: It's probably because of the way I coded this; I have a feeling the code is sort of 'bloated' because I am not that versed with the tricks used to streamline assembler code. :)

 

I have included my latest attempt in the first post (for some reason I can't add attachments to this post). They only move one speed, there is no collision detection with the UFO, the invaders don't shoot back, and there still are no shields. They also don't stop once they reach the ground.

 

I need to streamline the missile / invader collision too.

Link to comment

Hi Bob

Really amazing;i do not care about the speed.SI 7800 is great.

Thanks for sharing with us.It plays very well on the emulator.

What are the settings for the CC2 ?

Hope to see more.

greetings Walter

Link to comment

What gfx mode are you using, out of curiosity?

 

And I'd just dedicate 2K of RAM to the shields, you shouldn't be too tight for RAM with such a simple game, I'd think. Let's see...4 shields, each 22 pixels wide, assume you are using 320A or 320D so you have 8 pixels per byte, that means 12 bytes per page of RAM. Not too bad.

 

And I'm not a hardcore SI fan, but I don't find the ripple effect worth wasting a lot of time worrying about. I'd rather see you use 320B for the graphics and get the overlay behind the invaders!

 

That would be seriously kick-ass! :roll:

Link to comment

Sorry guys, I haven't been on much lately and I didn't see this until today.

 

@Walter - Thanks :( I have actually started from scratch again because what I was doing was not the correct way of handeling the invaders. I am still working on it!

 

@Bob - I am using 320A, and I will use RAM for the shields (thanks for that). I'm just curious on how to chip away the exact section of the shield that the shots hit, being that there is no hardware collision detection on the 7800! :-/ As far as the background, I actually thought of trying to replicate the 'moon' scenario, but I have to use the character set for the invaders, as there would be too many sprites (55 invaders + 4 shields + 3 shots + player + ufo) for each line of the display list. :cool:

 

Thanks!

Bob

Link to comment
...as there would be too many sprites (55 invaders + 4 shields + 3 shots + player + ufo) for each line of the display list. :cool:

 

Why do you include all those things in your total? Eleven invaders, two shots, and the four shields would be the max I could see.

Link to comment
...as there would be too many sprites (55 invaders + 4 shields + 3 shots + player + ufo) for each line of the display list. :cool:

 

Why do you include all those things in your total? Eleven invaders, two shots, and the four shields would be the max I could see.

 

If I were doing this with sprites, it's a possibility (as you get toward the bottom of the screen) that all of those things can occupy a particular zone. They don't have to all be there at the same time, but the provision has to be made for all of them... except the player, I guess, which would only be on the bottom row. At least that's how I understand the display list entry; if a sprite can occupy the zone a display list describes, it must be included in that display list.

 

Am I understanding that correctly?

Link to comment
At least that's how I understand the display list entry; if a sprite can occupy the zone a display list describes, it must be included in that display list.

 

There are two general styles of handling display lists: fixed allocation and dynamic allocation. Under fixed allocation, if there is any possibility that two particular sprites may occupy a zone simultaneously, both should be in the display list. Under dynamic allocation, a display list will only contain the sprites that are actually there at that moment.

 

Under neither scenario, however, is there any need to include all of the invaders, or to include invaders and the player. You could have one display list entry for (first-column invader or player), one for (second-column invader), etc. You know that the first-column invader from the first row will never share a zone with the first-column invader from the second row, so there's no reason for them to have separate DL entries.

Link to comment
@Bob - I am using 320A, and I will use RAM for the shields (thanks for that). I'm just curious on how to chip away the exact section of the shield that the shots hit, being that there is no hardware collision detection on the 7800! :-/ As far as the background, I actually thought of trying to replicate the 'moon' scenario, but I have to use the character set for the invaders, as there would be too many sprites (55 invaders + 4 shields + 3 shots + player + ufo) for each line of the display list. :cool:

supercat is mostly right, though he lost me in the specifics. I assume 16-line zones?

 

Anyway, having room for all the invaders in a zone is a moot point anyway, since writing all the invaders to DLs as sprites would take way too long anyway.

 

I actually was thinking about SI 7800 before I saw your blog, so I'll lay out how I thought I'd do it:

 

Use 320B/D, using 320D like 320A - i.e., using palette 0 or 4 gives you a monocolor bitmap. That's what I'm doing for the scrolling background in my WIP in the homebrew forum.

 

Then, use 320B 3-color tiles for the background - I think (?) that the arcade SI is 224 pixels wide, so you only need to display 28 tiles. Then use 320D characters/tiles for all the text and invaders. Use 320D sprites for everything else.

 

Hm. Actually, working out the timing, doesn't seem like it would work unless you used collapsing zones so that a row of invaders never overlapped another invader - but that would complicate everything else so much it probably wouldn't be worth it - unless. Hmmm.

Link to comment

@Supercat - Thanks for trying to explain, but as I say below I am just now finally understanding the 7800 Display List basics. You guys seem to be *extremely* knowledgable about the 2600, 7800, etc. I wish I was at that level.

 

@Bob - Talk about losing someone in the specifics! :D Please keep in mind I am just now finally understanding the basics of the 7800 Display List (List). BTW, I am using 8 line zones. All of the characters in SI are 8 pixels high (except the shields, and I just put them in two zones). Also, you are correct; SI is 224 pixels wide.

 

But there is another timing issue to worry about... All of this stuff has to happen and still be fast enough that the last invader zooms accross the screen! ...Which brings me to my next point: I took out the 'wave' of the invaders marching. They all move at once again. It was just too much, trying to keep track of which line to move at which frame... Keeping track of the current DLL and Screen Ram Line as to only move those 5 rows. The last invader didn't move very fast at all. So, I reverted back to how it was originally created.

 

BTW, can you have two character mode display lists in the same zone? If so, that could be a good way to do the background as well. (If that's what you meant, I apologize)

 

...

Collapsing Zones?

...

 

Bob

 

P.S. Another thing I noticed, is that I have to figure out how to tell when a whole outside column has been destroyed and allow the rest of the invaders to move that much farther toward the edge of the screen when marching... hmmm....

 

...Also, why does the color Red look so damn horrible in 320 mode? I tried it on two different TVs just to make sure it wasn't the TV and it looks the same. The UFO looks like it was already shot - a few times. You can barely make out the shape of the top row of invaders as well (I guess the 'red' part in the purple is doing it) :cool: I may make everything white, like the arcade. :(

 

 

Updated Binary in first post - Scoring was added, the shield sprites were added (although they don't do anything), and rack refresh was added.

Link to comment

Sorry to be so wonky...:(

 

Yes, you can have two char-mode entries in a single DL. That's how I'd do the background, but the main issue with that is really that there isn't time for MARIA to draw everything. Except there might be, since I didn't realize that the invader rows are 8 lines apart, so (with 8-line zones) you will never have two rows of invaders in the same zone.

 

So...

Background: 28 320B tiles = 264 MARIA cycles

Aliens: 11 320D tiles = 111 cycles

Shots: 3 320D sprites = 11 cycles each = 33 cycles.

Total = 408 cycles. Hmm. Probably still too many.

 

But in any case -

The UFO only overlaps with the shots, so for that DL you only need room for 2 sprites (UFO and player shot).

The middle zones (below the UFO and above the shields) only have aliens and shots, so you only need room in each DL for a single tile entry (aliens) and 3 sprites (alien shots and player shot).

The shield zones are the trickiest, they can have aliens, shields, and shots, so they'll need 1 tile entry (aliens) and 7 sprites (4 shields and 3 shots).

The bottom zone, with the player ship, can have aliens, shots, and the player, so you'll need room for 1 tile entry and 4 sprites.

So the biggest DL will be the shield-zone, with 8 entries. So you could just reserve 32 bytes for all the DLs except for that one; reserving 64 bytes for that one. Or, since RAM is tight, you could cut things even finer. In fact, you probably will want to cut things very fine, I just realized, since you will have a lot of zones since you are using 8-line zones. :D

 

But it really shouldn't take you very long to get things on the screen, you only have 14 objects:

5 alien rows, 1 UFO, 3 shots, 1 player, 4 shields. You should be able to write all those entries to the DL in under 20 scanlines, I would think. :D Leaves lots of time for other stuff.

 

EDIT: And to make this even longer...:cool:

Another thing I noticed, is that I have to figure out how to tell when a whole outside column has been destroyed and allow the rest of the invaders to move that much farther toward the edge of the screen when marching

Well, if you have the tile-maps for the invaders in RAM as 5 strips of 11 bytes, just use a loop to find the left-/right-most column that still has an invader. Something like...

	ldx #10
FindRightmostNonemptyColumnOuterLoop
lda AlienRAM,X
bne FoundAnAlien
lda AlienRAM+11,X
bne FoundAnAlien
lda AlienRAM+22,X
bne FoundAnAlien
lda AlienRAM+33,X
bne FoundAnAlien
lda AlienRAM+44,X
bne FoundAnAlien
dex
bpl FindRightmostNonemptyColumnOuterLoop
;--if we drop through here that means all aliens are gone!
jmp AllAliensKilled
FoundAnAlien
;--here X holds the column # (minus one) of the rightmost column
;	with an alien in it.

That assumes that you are using a zero value for a blank tile.

Link to comment

Thanks, Bob

 

Hmmm... ok you gave me something to think about. The code you have there I will have to use for all 5 rows and keep the outermost position for all 5. I'll give it a shot - thanks! :cool:

 

PS, you've got PM :(

Link to comment

How wide are the invaders and what is their spacing? If the invaders are three or more 'characters' wide, you'd use less MARIA time having a separate display-list item for each one than using a tile-map mode.

Link to comment

Hi!

 

The Invaders are two characters wide, right next to each other (which reminds me of something else; I have to do the fine-tuning collision detection between the shot and the invaders... right now you can't shoot in between them).

 

hmmm...

Link to comment
Hi!

 

The Invaders are two characters wide, right next to each other (which reminds me of something else; I have to do the fine-tuning collision detection between the shot and the invaders... right now you can't shoot in between them).

 

hmmm...

:cool:

 

I was going to mention that but I forgot. :(

 

When I was thinking about porting SI to the 7800 a few months ago I did some pixel counting...

 

The whole thing is based on 8x8 sprites/tiles.

 

Font is 5x7.

Aliens are 8x8 (top), 11x8 (middle), 12x8 (bottom)

 

Spacing is every 16 pixels; i.e., every alien, regardless of size, fills a 16x8 space.

Player ship is 13x8

Shields are 22x16

UFO is 16x7

 

There are 8 lines between rows of aliens.

 

Whole screen is 224x240.

3 rows of text at top (24 lines)

1 row of text at the bottom (8 lines)

 

So play area is 224x208.

Link to comment

Thanks Bob, for the stats. I had to take away 4 lines to fit on the standard screen (I had 208 lines to work with). I removed one line of text, and 3 lines of playfield.

 

...

 

This sucks.

 

I don't have 8 contiguous pages of memory free for the shields. I originally was doing the shields as 4 individual ones, when I realized I could save a few Display List entries by doing one long shield, only filled in where the 4 of them are supposed to be. But, I need to put them in RAM, so I need 8 pages (each line is on a different page). I'm even using zero-page RAM for all of my game variables so far. Here's my RAM:

 

;******** display list ram

dllist = $1800 ; $400 bytes

;$1c00 - $203f left

 

;******** screen ram

charmem = $2200

lhead = $2200

lscore = $2220

l00 = $2240

l01 = $2260

l02 = $2280

l03 = $22a0

l04 = $22c0

l05 = $22e0

l06 = $2300

l07 = $2320

l08 = $2340

l09 = $2360

l10 = $2380

l11 = $23a0

l12 = $23c0

l13 = $23e0

l14 = $2400

l15 = $2420

l16 = $2440

l17 = $2460

l18 = $2480

l19 = $24a0

l20 = $24c0

l21 = $24e0

l22 = $2500

lstat = $2520

;$2540 - $27ff left

 

I've been trying to move things around, but no matter what I won't have enough free. :cool:

Link to comment
But, I need to put them in RAM, so I need 8 pages (each line is on a different page). I'm even using zero-page RAM for all of my game variables so far.

 

Perhaps you could use a display list interrupt to help out with the shields. Unfortunately, the timing for such things does not seem to be accurate in emulation, so you may need some special code to determine whether you're running in an emulator and, if so, perform an extra STA WSYNC.

 

If you use a display list interrupt, you will probably be able to arrange the shield memory almost any way you want. Suppose you want each shield to be represented by 48 bytes, all in the same 256-byte page. The "guts" of the DLI would then be something like:

  sta WSYNC
 ldy #[>shield1start]-7
 lda #<[shield1start]
 sec
 nop; Want to start store after MARIA takes its cycles.
loop:
 sty shield1_h; Patch the display list
 sty shield2_h
 sty shield3_h
 sty shield4_h
 sta shield1_l
 adc #<[shield2start-shield1start-1]
 sta shield2_l
 adc #<[shield3start-shield2start]
 sta shield3_l
 adc #<[shield4start-shield3start]
 sta shield4_l
 adc #<[shield1start-shield4start+3]; Advance 3 bytes per row
 sta WSYNC
 iny
 cpy #>shield1start
 bcc loop

Eleven 3-cycle instructions and six two-cycle instructions, total 45 cycles. I think there's room for that. You'd need two copies of the routine to run in quick succession, one to update the display list for the upper eight lines and the other for the lower. You'd also probably have to have the DLI trigger on the zone before the first shield zone, save registers on the stack, and count lines until you get to the first shield zone. That shouldn't be a particular problem, though.

Link to comment

Thanks, Supercat - I'm going to need to read this over a few times before I follow what's going on here... :cool:

 

BTW, I alse moved the Screen RAM to be just under the DLL & DL, so it looks like this now:

 

;******** display list ram

dllist = $1800 ; $400 bytes for DLL & DL

charmem = $1c00 ; begin screen ram

lhead = charmem+$00

lscore = charmem+$20

l00 = charmem+$40

l01 = charmem+$60

l02 = charmem+$80

l03 = charmem+$a0

l04 = charmem+$c0

l05 = charmem+$e0

l06 = charmem+$100

l07 = charmem+$120

l08 = charmem+$140

l09 = charmem+$160

l10 = charmem+$180

l11 = charmem+$1a0

l12 = charmem+$1c0

l13 = charmem+$1e0

l14 = charmem+$200

l15 = charmem+$220

l16 = charmem+$240

l17 = charmem+$260

l18 = charmem+$280

l19 = charmem+$2a0

l20 = charmem+$2c0

l21 = charmem+$2e0

l22 = charmem+$300

lstat = charmem+$320

;$1f40 - $203f free

 

 

This leaves me with $2200-$27FF free (still not enough, but at least it contiguous)

Link to comment

I got it:

 

I was able to squeeze another $100 bytes out of the Display List List, so I could then move it to the $2200 area. The Screen RAM still immediately followes it:

 

;******** display list ram

dllist = $2200 ; $300 bytes for DLL & DL

charmem = $2500 ; begin screen ram

lhead = charmem+$00

lscore = charmem+$20

l00 = charmem+$40

l01 = charmem+$60

l02 = charmem+$80

l03 = charmem+$a0

l04 = charmem+$c0

l05 = charmem+$e0

l06 = charmem+$100

l07 = charmem+$120

l08 = charmem+$140

l09 = charmem+$160

l10 = charmem+$180

l11 = charmem+$1a0

l12 = charmem+$1c0

l13 = charmem+$1e0

l14 = charmem+$200

l15 = charmem+$220

l16 = charmem+$240

l17 = charmem+$260

l18 = charmem+$280

l19 = charmem+$2a0

l20 = charmem+$2c0

l21 = charmem+$2e0

l22 = charmem+$300

lstat = charmem+$320

 

 

So now I have $1800-$203F free for the shields. :( Now I just need to figure out how to make them deteriorate with each shot that hits them.

 

 

*EDIT* - Actually it looks like I have to find another $40 bytes - the screen RAM extends to $283F... Into the shadow area. I'll fix it :cool:

Link to comment

What do all the labels denote? What is "screen RAM"? With one big long sprite in RAM, using 320A, you need...

 

Hm. Counting more pixels, the shields, oddly enough, are 22x16 but are spaced with 23 pixels between each. That will make for a weird memory mapping if you do it as one sprite, besides all the wasted RAM between. Or wait. Are you using tiles/chars for the shields? That would probably use the least RAM.

Then you just need 40 bytes for the tile-map (20 for each zone) plus 6 bytes for each shield row, laid out:

   org ShieldRAM
;--bottom line of shields
Shield1Top ds 6
Shield1Bottom ds 6
Shield2Top ds 6
Shield2Bottom ds 6
Shield3Top ds 6
Shield3Bottom ds 6
Shield4Top ds 6
Shield4Bottom ds 6

  org ShieldRAM+256
Shield2ndLine ds 48
  org ShieldRAM+512
Shield3rdLine ds 48
...

And etc.

 

Anyway, my point is that you aren't going to be using the vast majority of that RAM space, so stick a bunch of other variables there. If your code supports it, you could move a bunch of your DLs in between there. :cool:

Link to comment

Hey Bob:

 

The labels I am using refer to the memory locations I am storing the DL, DLL, and Character Memory. I went just over the first section of usable RAM (to $2840 instead of $27FF).

The 'Screen RAM' I am referring to is the RAM for each line of the screen in character mode. There are 28 ($1C) bytes per line (I rounded it out to $20 becuase it was easier to work with) that denote the characters on the line (It's what gets manipulated for the invaders to march), as well as the score line and the status line at the bottom. (Character Memory) I hope I explained that correctly...

 

I am using one long sprite instead of 4 separate ones because: It makes it easier to check if there is a collision; checking if a pixel is on for one long sprite instead of 4 separate sprites in different places (at least to me it does). I have to check each of the up to 16 vertical pixels of the shields to find one that is on at the x position of the player's (or invader's) shot, and remove it if it is. Also, the other reason is there are 6 fewer DL entries, 30 less bytes to process (and to take up RAM).

 

I am using sprites (not Character Mode) for the shields. I think I *have* to use character mode - the spaces between the shields is not an even '24', and I have to chip away bits of the shield from each shot - I can't do that with character mode, can I?

 

By all means if I am going about this the wrong way, please let me know. As (I'm sure) you can tell, my knowledge is very limited here.

 

Thanks, Bob & Supercat

Bob

Link to comment

Guest
Add a comment...

×   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...