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

Some progress on Space Invaders 7800


PacManPlus

3,093 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



How did they manage to do the shields on the 2600 version? I would have thought that in comparison, the 7800 would have been a snap.

 

I get that they're using sprites... but how are they getting them to deteriorate?

Link to comment
I get that they're using sprites... but how are they getting them to deteriorate?

 

The Atari 2600 simply keeps the shapes of the shields in RAM. There are three of them, and they're probably about 10 rows high, so 30 bytes for the whole set.

Link to comment
Hm. Counting more pixels, the shields, oddly enough, are 22x16 but are spaced with 23 pixels between each.

 

So from the leftmost shield bit to the rightmost bit would be 167 pixels? If you're in an 8-pixels-per byte mode, you could do that with one DL entry; otherwise you'll need two.

 

Simplest in that case is probably to allocate 32 bytes per shield row. You wouldn't actually be displaying all of it (no reason for MARIA to fetch blank bytes) but leaving the unused areas blank could ease collision detection.

 

If you set up the display lists before the beam gets there, the DLI loops could be very simple:

; Setup:
 lda #[>shield1_ram]-7
 sta SHIELD_DL1_H
 lda #[>shield2_ram]-7
 sta SHIELD_DL2_H
 lda #<shield1_ram
 sta SHIELD_DL1_L
 sta SHIELD_DL2_L
 ... end of setup

ISR: (in RAM)
 jmp xxxx

ISR for this part:
 sta WSYNC
 cld
 pha  
 lda #<shield1_ram+32
 clc  
loop1:		; Start AFTER first line has been output
 sta SHIELD_DL1_L
 inc SHIELD_DL1_H
 sta WSYNC
 adc #32
 bcc loop1
 sta WSYNC
 lda #<shield2_ram+32
 clc
 nop
loop2:	   ; Starts after first line of second group of eight has been output
 sta SHIELD_DL2_L
 inc SHIELD_DL2_H
 sta WSYNC
 adc #32
 bcc loop2
 lda # [next DLI address MSB]
 sta ISR+2
 pha
 rti

All your shields would fit nicely in two pages of RAM. If you like, I can test and refine the above code to get it working properly on real hardware.

Link to comment

Hey Supercat - it's funny; any time I feel like I'm starting to understand more of the 7800, all I have to do is look at your code and I feel stupid again :cool:

 

Before I do anything I will continue to read it until I understand completely what's going on...

 

So I'm guessing what I was planning to do with the shields won't work? (keep the bitmap itself in RAM and once the 'Y' value of a shot is in the range of the shields, subtract the 'X' value of that shot from the shield sprite for each of the 16 scanlines and remove if that section exists).

 

Also, there is another issue that I just found. In the arcade version, when a shot ends or hits a shield, there is a small explosion graphic that gets shown for about 1/4 of a second. That graphic is then XOR'ed with the section of the shield it hit to remove it. This goes through more that one scanline at a time, which will make things quite difficult (for me).

 

hmmm....

Link to comment

Hi Bob

Your last version works great.Cannot wait to see more.But the moving of the invaders does not work right.

greetings Walter

Link to comment
So I'm guessing what I was planning to do with the shields won't work? (keep the bitmap itself in RAM and once the 'Y' value of a shot is in the range of the shields, subtract the 'X' value of that shot from the shield sprite for each of the 16 scanlines and remove if that section exists).

 

That's the idea, but different ways of mapping the shield graphics in memory will make things easier or harder.

 

My personal suggestion would be to use something like the DLI handler I sketched out so that the 16-high shield will be held in two pages, 32 bytes/row. That should be more convenient than using 32 bytes out of every 256 throughout the whole 4K.

 

The basic logic would thus be something like:

 ; Prepare X pointer offset/sub
 lda x_pos
 and #7
 sta x_pos_sub
 lda x_pos
 lsr
 lsr
 lsr
 sta x_pos_ofs
; Prepare pointer to data
 ldx shot_y_pos
 lda y_table_h,x
 sta ptr_h
 lda y_table_l,x
 adc x_pos_ofs
 sta ptr_l
; Check for collision:
 ldx x_pos_sub
 ldy #0
 lda (ptr),y
 and bit_mask1,x   ; See if top center of missile hits
 bne missile_collision

Explosions would be simple if the missiles only exploded in such fashion that no part of the explosion would be outside the bitmap. I'm not sure that's realistic (though if you have enough memory to extend the bitmap outside the area of the shields, it would make things easy). The basic explosion would be:

  ldx x_pos_sub; If it isn't already
 ldy #0
 lda (ptr),y
 and missile_mask1a,x
 sta (ptr),y
 iny
 lda (ptr),y
 and missile_mask1b,x
 sta (ptr),y
 ldy #32
 lda (ptr),y
 and missile_mask2a,x
 sta (ptr),y
 iny
 lda (ptr),y
 and missile_mask2b,x
 sta (ptr),y
 etc.

The code ends up being a little bulky, but not outrageous. While it would be possible to rewrite the code to use a loop, it would run much slower than with inline code; unless code space is at an absolute premium I wouldn't recommend doing it.

 

BTW, one approach to handling the possibility of an explosion that occurs partially outside the shield area would be to have two copies of the code, one of which draws things from the top down, and one which draws things from the bottom up. If you had a list of entry points, you could then easily hit only those rows that were within the shield bitmap.

Link to comment

Hey Supercat:

 

Before I read your blog comment here (while this site was down) I made a little progress in this department. I intend to read and attempt to fully understand what you are doing in the above code (because I would bet a year's salary that it's *much* more efficient that what I've done). But, I just wanted to show what I was able ot figure out:

;******** remove piece of shield that shot hit
;******** inputs: temp - y position of shot, temp2 - x position of shot
;******** uses: a, x, y, temp, temp2, tmpadrl, tmpadrh
ChipShield
lda temp	;get y value of shot to shield
cmp #$90	;#$90 is the y-coordinate of the top of the shield
bcc ChipShieldRts;if the shot is higher than the shield, exit
sec
sbc #$90	;shift origin to the beginning (#$00)
cmp #$10	;#$10 (16 decimal) is now the bottom of the shield - two rows of 8
bpl ChipShieldRts;if the shot is still lower than the shield, exit
tax
lda Shield2ShotL,x;this gets the beginning address of the bitmap definition for each pixel line
sta tmpadrl
lda Shield2ShotH,x
sta tmpadrh

lda temp2	;get x value of shot to shield
sec
sbc #$25	;shift origin
bmi ChipShieldRts;if the shot is to the left of the left-most shield, exit
tax
lsr	;each line of bitmap is 21 bytes - we need to figure the offset here
lsr	;divide by 4 (pixels per character may be 8, but position is 4)
tay	;this is the byte offset where the shot hit the shields
lda (tmpadrl),y;load the byte at the position the shot hit
and Shot2Bit,x;'AND' it with the 'fine' position of the shot (shot bitmap is $80)
beq ChipShieldRts;if it's already erased (from a previous shot), exit
lda (tmpadrl),y;re-load the value (to be erased)
and Clear2Bit,x;remove the part the shot hit
sta (tmpadrl),y;store it back
jsr RemoveP1Shot;remove the player's shot
ChipShieldRts
rts
Shot2Bit
.byte $c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03
.byte $c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03
.byte $c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03
.byte $c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03
.byte $c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03
.byte $c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03
.byte $c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03
Clear2Bit
.byte $3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc
.byte $3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc
.byte $3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc
.byte $3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc
.byte $3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc
.byte $3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc
.byte $3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc,$3f,$cf,$f3,$fc
Shield2ShotL
.byte <(shields+$700),<(shields+$600),<(shields+$500),<(shields+$400)
.byte <(shields+$300),<(shields+$200),<(shields+$100),<(shields+$000)
.byte <(shields+$720),<(shields+$620),<(shields+$520),<(shields+$420)
.byte <(shields+$320),<(shields+$220),<(shields+$120),<(shields+$020)
Shield2ShotH
.byte >(shields+$700),>(shields+$600),>(shields+$500),>(shields+$400)
.byte >(shields+$300),>(shields+$200),>(shields+$100),>(shields+$000)
.byte >(shields+$720),>(shields+$620),>(shields+$520),>(shields+$420)
.byte >(shields+$320),>(shields+$220),>(shields+$120),>(shields+$020)

 

Keep in mind, this is very early; I plan to XOR the actual shot sprite like the arcade does - after going over your code (which I thank you for, BTW) :cool:

 

So... how bad is my code? :( I actually repeat this subroutine 3 times (because the shot moves in increments of 3 pixels, and I have to clear the two pixels under where the shot hit).

 

I have included the bin in the first post. The following changes are there:

1) Changed colors to be more 'compatable' with TVs

2) Added preliminary collision detection for the UFO - no points awarded, it just turns into an explosion graphic and keeps going.

3) Added Shields, and preliminary shot detection on the shield

4) THE INVADERS NOW REACH THE SIDE OF THE SCREEN CORRECTLY!!! :D :P :D

5) When shot, the invaders temporarily turn into an explosion graphic, and pause (like the arcade).

6) If an invader reaches the bottom of the screen, the game ends (endless loop for now)

7) The invaders drop one line after each rack. No boundary checking yet, so the game eventually becomes unplayable because they are too low.

 

BTW, does anyone have the point value list table of the UFO for each player shot?

 

Thanks!

Bob

Link to comment
So... how bad is my code? :cool: I actually repeat this subroutine 3 times (because the shot moves in increments of 3 pixels, and I have to clear the two pixels under where the shot hit).

 

Was it only enemy shots that exploded bits off the shield, while the player shots just chipped away at it? It's been ages since I've played that game.

 

Doing a compare, then a subtract (of the compared value), and then a third compare is a bit wasteful. A better approach, if you want to map values 144-159 to 0-15, would be:

  lda ypos
 sec
 sbc #160; Values 144-159 will map to 240-255, with carry clear
 adc #16 ; Now they'll be 0-15, with carry set (carry will be clear for all other values)

An even better approach, though it's only usable if the starting range and length have a suitable relationship (which is present in this particular example) would be:

  lda ypos
 eor #144
 cmp #16

Here, carry will be clear if the shot position is in range (the initial carry state doesn't matter).

 

I would suggest having the 'x' coordinate of the shot added into the zero-page pointer, rather than into the Y register. That will facilitate the collision/erasure code:

; Assuming pointer is all set up
 ldy #0
 lda (ptr),y
 ldy #32
 ora (ptr),y
 lda #64
 ora (ptr),y
 and shotmask
 beq not_hit
; y is still 64
 eor #255
 tax
 and (ptr),y
 sta (ptr),y
 ldy #32
 txa
 and (ptr),y
 sta (ptr),y
 ldy #0
 txa
 lda (ptr),y
 sta (ptr),y

 

BTW, a useful observation: if you use 32 bytes/row for the shields, you may not have to check whether the X position is in range to hit the shield. If it's out of range, it will 'wrap' in such a way as to hit a blank part of the next line. You may want to do the check, for various reasons, but it isn't strictly necessary.

Link to comment
Was it only enemy shots that exploded bits off the shield, while the player shots just chipped away at it? It's been ages since I've played that game.

Actually both exploded bits off the shield, although the player's shots have a different explosion bitmap than the invaders do.

 

I am looking at incorporating your changes to the x & y coordinate mapping now. Although I may extend the shield section of the bitmap to all 28 horizontal character positions (the playfield is 28 characters wide), and just check the exact location of the shot in the bitmap field. I thought this may be a good idea in case I wanted to offer different shield shapes (like Gorf, that shapes the shield like an arc and extends the entire length of the screen)... Good idea?

Link to comment
I am looking at incorporating your changes to the x & y coordinate mapping now. Although I may extend the shield section of the bitmap to all 28 horizontal character positions (the playfield is 28 characters wide), and just check the exact location of the shot in the bitmap field. I thought this may be a good idea in case I wanted to offer different shield shapes (like Gorf, that shapes the shield like an arc and extends the entire length of the screen)... Good idea?

 

You only need to display the width of shield that actually has 'stuff' in it, but having a bitmap allocated for the whole width would simplify things I would think. I would suggest 32 bytes/row rather than 28, so that no row will cross a page. If rows can cross pages, then the addressing code becomes a little harder.

Link to comment

Thanks :cool:

 

Even though I'm only using 28, I'm leaving space for 32 (there are four extra bytes at the end of each pixel row that I'm not copying). I had a feeling it would be easier on a $20 byte boundary :(

 

ok, I'm back to work :D

Link to comment

Hi:

 

Thanks guys! :)

 

Just got back from Mohegan Sun (I didn't win) :D. I actually worked on this while I was there :)

 

I think I have it to where the player's shot explosion removes itself from the shield (see first post for bin). The only thing, is that I'll have to use this subroutine up to a maximum of 4 times (if dual players, one for each player's shot and one for each invader's shot). I don't think there will be enough CPU time to do all of that. Is there a way to reduce this subroutine?

 

The Characters at D0/D1, D2/D3, D4/D5, and D6/D7 have the inverted explosion graphics at different positions within the shot's byte position. The D0/D1 and D2/D3 need the shield RAM byte to be subtracted by 1 because the graphics bleed into the previous byte.

 

One thing that bothers me, though, is that certain shield locations cannot be hit. The shot passes right through them. I guess that's because the y position of the shot gets 3 added to it each frame, so it can 'miss' an area of the shield if it's between those values. :D

 

;******** remove piece of shield that player shot hit
;******** inputs: temp - y position of shot, temp2 - x position of shot
;******** uses: a, x, y, temp, temp2, tmpadrl, tmpadrh
ChipShieldPlayer_Rts2
rts
ChipShieldPlayer
lda temp;get y value of shot to shot
eor #144;Exclusive OR it with #$90 (the beginning 'y' of the shield)
cmp #16	;Carry will be clear if shot position is in range
bcs ChipShieldPlayer_Rts2
sta shieldrow
tax
lda Shield2ShotL,x
sta tmpadrl
lda Shield2ShotH,x
sta tmpadrh

lda temp2;get x value of shot
sec
sbc #leftside;shift origin
sta shieldcol;store it
tax
lsr
lsr	;divide by 4 (pixel definition may be 8, but pos is 4)
sta shieldbyte;this is the byte offset where the shot hit the shields
tay
lda (tmpadrl),y
and Shot2Bit,x;did the shot hit a section of the shield?
beq ChipShieldPlayer_Rts2;no, exit
ChipShieldPlayer_SetUp
lda #$00
sta shieldidx;we will need to remove 8 rows of pixels
lda shieldrow;get the current collision row
sec
sbc #$03;we need to go 3 pixels higher that where the shot hit
sta shieldrow
ChipShieldPlayer_Loop
lda shieldrow;get the current shield row (of 16)
bmi ChipShieldPlayer_Next;if it's not in range (0-15) skip
tax
lda Shield2ShotL,x;get the start of ram for this row
sta tmpadrl
lda Shield2ShotH,x
sta tmpadrh
lda shieldidx;get the current explosion row (of 8)
clc
adc #>fontdata;find the pointer to the graphic data
sta tmprowh
lda #$00
sta tmprowl
ldy shieldcol
lda Clear2Bit,y
tay
lda (tmprowl),y;get the current explosion byte definition (1st byte)
sta shieldand1
iny
lda (tmprowl),y;get the current explosion byte definition (2nd byte)
sta shieldand2
			
ldy shieldcol;do we have to subtract 1 from the byte column?
lda Shot2Offset,y
clc
adc shieldbyte
tay
lda (tmpadrl),y;and get the current ram location of the shot shield
and shieldand1
sta (tmpadrl),y;'AND' them together and put the value back
iny
lda (tmpadrl),y
and shieldand2
sta (tmpadrl),y
ChipShieldPlayer_Next
inc shieldrow
lda shieldrow
cmp #$16
bpl ChipShieldPlayer_Rts
inc shieldidx
lda shieldidx
cmp #$08
bpl ChipShieldPlayer_Rts
bmi ChipShieldPlayer_Loop
ChipShieldPlayer_Rts
jmp RemoveP1Shot;remove the player's shot

Shot2Bit
	.byte $c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03
	.byte $c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03
	.byte $c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03
	.byte $c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03
	.byte $c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03
	.byte $c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03
	.byte $c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03,$c0,$30,$0c,$03
Shot2Offset
	.byte $ff,$ff,$00,$00,$ff,$ff,$00,$00,$ff,$ff,$00,$00,$ff,$ff,$00,$00
	.byte $ff,$ff,$00,$00,$ff,$ff,$00,$00,$ff,$ff,$00,$00,$ff,$ff,$00,$00
	.byte $ff,$ff,$00,$00,$ff,$ff,$00,$00,$ff,$ff,$00,$00,$ff,$ff,$00,$00
	.byte $ff,$ff,$00,$00,$ff,$ff,$00,$00,$ff,$ff,$00,$00,$ff,$ff,$00,$00
	.byte $ff,$ff,$00,$00,$ff,$ff,$00,$00,$ff,$ff,$00,$00,$ff,$ff,$00,$00
	.byte $ff,$ff,$00,$00,$ff,$ff,$00,$00,$ff,$ff,$00,$00,$ff,$ff,$00,$00
	.byte $ff,$ff,$00,$00,$ff,$ff,$00,$00,$ff,$ff,$00,$00,$ff,$ff,$00,$00
Clear2Bit
	.byte $d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6
	.byte $d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6
	.byte $d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6
	.byte $d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6
	.byte $d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6
	.byte $d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6
	.byte $d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6,$d0,$d2,$d4,$d6
Shield2ShotL
	.byte <(shields+$700),<(shields+$600),<(shields+$500),<(shields+$400)
	.byte <(shields+$300),<(shields+$200),<(shields+$100),<(shields+$000)
	.byte <(shields+$720),<(shields+$620),<(shields+$520),<(shields+$420)
	.byte <(shields+$320),<(shields+$220),<(shields+$120),<(shields+$020)
Shield2ShotH
	.byte >(shields+$700),>(shields+$600),>(shields+$500),>(shields+$400)
	.byte >(shields+$300),>(shields+$200),>(shields+$100),>(shields+$000)
	.byte >(shields+$720),>(shields+$620),>(shields+$520),>(shields+$420)
	.byte >(shields+$320),>(shields+$220),>(shields+$120),>(shields+$020)

 

Also, I give point values for shooting the ufo now. (see first post)

*NOTE*, please ignore that shooting the shield sometimes gives you points, I know what that is, and I will fix it.

 

Bob

Link to comment

I think you broke something with the invaders march. They get faster too quickly and then slow down to a crawl. Also when you clear the screen it just stops instead of starting a new round like the previous version.

 

Allan

Link to comment
I think you broke something with the invaders march. They get faster too quickly and then slow down to a crawl. Also when you clear the screen it just stops instead of starting a new round like the previous version.

 

Allan

 

Yes, That has to do with when you get 'points' for shooting the shields. The player's shot has already been removed, but it's still checking for collisions with the invaders. I will fix that in the next attachment. I am going to separate the collision checks into a separate subroutine, and exit once a collision has been detected.

 

I'm hoping that the above routine can be condensed somewhat. I also PM'ed opcode to ask if he has the 'UFO point value' table, indexed by player's shot.

 

BTW, Allan, hope all is well. I think in a few months I will be having another 'Classic Gaming Night'. :)

Link to comment
I think I have it to where the player's shot explosion removes itself from the shield (see first post for bin). The only thing, is that I'll have to use this subroutine up to a maximum of 4 times (if dual players, one for each player's shot and one for each invader's shot). I don't think there will be enough CPU time to do all of that. Is there a way to reduce this subroutine?

 

The hit test is reasonably fast, though I repeat my suggestion that you include the X-coordinate offset into the table so that you can use three different Y values to test three lines at once (see my collision check code above). I should add a few slight addenda to that, though:

 

(1) You may find it helpful to have some extra rows of shield data (blank), so as to avoid boundary cases (e.g. shots tests or explosions that are partially within the shield). Since each row only requires 32 bytes, you should be able to afford four rows above/below pretty easily.

 

(2) Alien bombs and player shots should use separate routines for collision detection since, among other things, the bombs should test the upper pixel first while shots test the lower one first.

 

(3) The routine to chip out the shield should look something like:

hit: ; Assume Y indicates where we are within the shot
; We'll add $FF80+Y to ptr to point to top of explosion
 tya
 clc
 adc #128 ; Offset to find top of explosion
 adc ptr
 sta ptr
 lda #255
 adc ptr+1
 sta ptr+1
 lda xpos
 and #3
 asl
 asl
 asl
 tax
 ldy #0
explodeLp:
 lda explodeL,x
 and (ptr),y
 sta (ptr),y
 iny
 lda explodeR,x
 and (ptr),y
 sta (ptr),y
 inx
 tya
 adc #31 ; Carry is clear before adc
 tay
 bcc explodeLp

Note that there are four different explosion shapes based upon the X offset of the bomb/shot. This will require 64 bytes for each type of explosion, but avoids any need for shifts. The explosion loop does not test for any out-of-range conditions; such tests could be added, but if you can spare the 256 bytes to add a 4 rows above and 4 rows below the shields, that would simplify things.

Link to comment

@Allan: Ok, I fixed the 'invaders marching' / 'points for shield' bug, attachment in first post. If there are some tiny areas that happen to be left that can't be hit, I don't think that's a big deal. I wouldn't think anyone wastes their time shooting away all of the shields. Even if the invaders aren't shooting, they get to drop a few levels by the time all of the shields are gone.

 

@Supercat: I'm sorry, I didn't mean to make you repeat yourself, I just didn't follow that completely the first time around. Did you actually compress that entire routine I posted into those few lines above? :) ... I *need* to understand this routine if that's the case. I will be studying it :D

Thank you!!!!! :D BTW, I plan on having the shields move in one of the options (like the 2600 version). Does that change anything?

 

Ok, I'm pretty close to an actual game here... two big things left: 1) make the invaders shoot and 2) control the ufo. I can then work on the options, and two player dual mode :D Oh crap... I just realized that for two players alternating, I have to copy the remaining invaders and shield to a temporary area... :)

 

BTW, does anyone know the timing on when the UFO comes out?

Link to comment
BTW, Allan, hope all is well. I think in a few months I will be having another 'Classic Gaming Night'. :)

 

I hope so. I wanted to have one myself but my home construction has taken a lot longer than I wanted. I'm looking forward to some gaming with real people. We should get together some time for some game designing/programming time. I love the week-end programming/gaming sessions they have in Europe all the time. Nothing but pizza and soda and programming and gaming and a little sleep in between.

 

Allan

Link to comment

Sounds cool Allan :)

 

Ok, I've updated the following things:

 

1) Shots are not auto-fire (like the arcade) and delay when hitting something.

2) Invaders now start at the correct row for each level (had to do a little adjusting for the difference in the size of the screen)

3) YOU CAN NOW SHOOT BETWEEN INVADERS! did some closer collision detection, It may appear for a shot to go through the very edge of an invader but it seems to work ok. :) Let me know if I should adjust anything. But, please remember, even though the bitmap for the invaders is based on 16 pixels (two bytes in 320A mode), everything is accessed as 8 pixels (two bytes in 160 mode). That caught me quite a few times while doing this.

 

See first post for attachment.

 

Supercat: Can you elaborate on this line: "hit: ; Assume Y indicates where we are within the shot" Is this the y position of the shot within the 16-pixel shield area?

Also, is there a way I can use the interrupt to check if a console switch was hit and store the value in a variable?

 

...I'm saving the sound for last. :D

Link to comment
Supercat: Can you elaborate on this line: "hit: ; Assume Y indicates where we are within the shot" Is this the y position of the shot within the 16-pixel shield area?

 

Basically, assume that (ptr),y is the address where the hit was detected. Though actually my hit detection earlier wouldn't be that precise come to think of it. So perhaps it should be:

 ; Assumes 'mask' holds the pixel mask; assume we want to process a hit with the LOWEST Y value that contains a pixel
 ldy #64
 lda (ptr),y
 ldy #32
 ora (ptr),y
 ldy #0
 ora (ptr),y
 and mask ; If any of those bytes had the 'mask' pixel set, this will be NZ.
 beq no_hit
 and (ptr),y; See if hit occurred when Y=0
 bne got_hit
 ldy #32
 lda mask
 and (ptr),y; See if hit occurred when Y=32
 bne got_hit
 ldy #64  ; We know we had a hit--it must have been when Y=64
got_hit:
; Now process explosion etc.

no_hit:
; Handle the no-hit case.

 

You could if you like use the faster logic to decide whether a hit occurred and the slower logic to figure out where; that would improve speed when a hit does not occur, but

 

Also, is there a way I can use the interrupt to check if a console switch was hit and store the value in a variable?

 

You could, but why not do it once per frame in the main loop?

Link to comment

Thank you Supercat :)

 

Thanks Walter!!! :D

 

Ok - next step

Things Added:

 

1) UFO point table based on player's shot (but for now it doesn't match the arcade yet)

2) Slowed UFO down to more closely match arcade speed

3) Added Invader shots (no collision detection yet)

 

I need to work on the frequency of the invader shots.

In the arcade, they don't seem to *constantly* shoot at you. There seems to be a variable delay between them. Also, most of the invader shots seem to be in the player's general area, with one or two not so close. Need to try and replicate that.

 

Updated bin and screenshot in first post.

Link to comment

Thanks again Walter :)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

WE HAVE COLLISION DETECTION FOR INVADERS SHOTS! :)

 

 

 

This game is now actually playable :D Supercat, I have not implemented your code yet (although I think I will have to, I can't have much CPU time left per frame). There might be one issue with it - If you recall, I am only using 8 pages of RAM for the Shield. There are 16 lines for the shield, therefore I started the first 8 rows in <$shields>, and added the last 8 rows in <$shields+$20> (being that each RAM line is only $20 long). Does the code you wrote assume all 16 rows of RAM are each contiguous page?

 

 

Update in first post.

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