Lay some more groundwork for animating centipede segments. We now have an array of 96 (97 actually) entries which describe the position of the segment now or in the past. By keeping past information, body segments which follow head segments will take no calculation to update. We just have to animate head segments and body segments will follow them 8 pixels behind automatically.

This commit is contained in:
Jeremy Rand 2020-09-07 22:35:32 -04:00
parent 3b541f8482
commit 36617cbf9d
3 changed files with 153 additions and 55 deletions

View File

@ -17,13 +17,22 @@ gameSegments start
SEGMENT_MAX_NUM equ 12
SEGMENT_MAX_OFFSET equ SEGMENT_MAX_NUM*2-2
SEGMENT_STATE_NONE equ 0
SEGMENT_STATE_HEAD equ 1
SEGMENT_STATE_BODY equ 2
SEGMENT_STATE_NONE equ 0
SEGMENT_STATE_HEAD equ 1
SEGMENT_STATE_POISONED_HEAD equ 2
SEGMENT_STATE_BODY equ 3
SEGMENT_DIR_LEFT equ 0
SEGMENT_DIR_RIGHT equ 1
SEGMENT_DIR_DOWN equ 0
SEGMENT_DIR_UP equ 1
; You would think I would need "facing up" variants here also. When the centipede gets to the bottom of
; the screen, it starts traveling up again and when it turns, you would think it would face up. Turns out
; the real arcade system uses "facing down" sprites even when the centipede is moving up. So, I guess I
; will too. I suspect that the players tend not to notice because by the time the centipede is traveling
; up, they are pretty occupied by the fact that they are now surrounded by segments.
SEGMENT_FACING_LEFT equ 0
SEGMENT_FACING_DOWN_LEFT equ 32
SEGMENT_FACING_DOWN equ 64
@ -35,46 +44,55 @@ drawSegments entry
ldx #SEGMENT_MAX_OFFSET
drawSegments_nextSegment anop
lda segmentStates,x
beq drawSegments_skipSegment
bne drawSegments_cont
jmp drawSegments_skipSegment
lda segmentFacing,x
clc
adc segmentSpriteOffset
tay
drawSegments_cont anop
phx
lda segmentStates,x
cmp #SEGMENT_STATE_HEAD
beq drawSegments_head
cmp #SEGMENT_STATE_BODY
bne drawSegments_head
jsl segmentBodyJump
bra drawSegments_handleTiles
drawSegments_head anop
jsl segmentHeadJump
; By the time we come back from segment*Jump, the X register no longer has the original 0-22
; offset. Instead, we have a position offset which goes from 0-190. But that is good because
; we need to use that offset to update our dirty tiles.
drawSegments_handleTiles anop
lda #TILE_STATE_DIRTY
ldy segmentTileOffsetsUL,x
sta tileDirty,y
ldy segmentTileOffsetsUR,x
sta tileDirty,y
ldy segmentTileOffsetsLL,x
sta tileDirty,y
ldy segmentTileOffsetsLR,x
sta tileDirty,y
; We do have to handle non-game tiles. When centipede reaches the bottom, new segements are
; added randomly in from the side. That segment needs to be clipped so we need to use non-game
; tiles to do that clipping for us.
_dirtyGameOrNonGameTileX segmentTileOffsetsUL
_dirtyGameOrNonGameTileX segmentTileOffsetsUR
_dirtyGameOrNonGameTileX segmentTileOffsetsLL
_dirtyGameOrNonGameTileX segmentTileOffsetsLR
; Get our original 0-22 offset we are iterating through that we pushed earlier because we know
; it was going to get trashed.
plx
drawSegments_skipSegment anop
dex
dex
bpl drawSegments_nextSegment
bmi drawSegments_done
jmp drawSegments_nextSegment
drawSegments_done anop
rtl
segmentHeadJump entry
lda segmentPosOffset,x
tax
lda segmentFacing,x
clc
adc segmentSpriteOffset
tay
lda segmentScreenShifts,x
beq segmentHeadJump_noShift
@ -99,6 +117,14 @@ segmentHeadJump_jumpInst anop
nop
segmentBodyJump entry
lda segmentPosOffset,x
tax
lda segmentFacing,x
clc
adc segmentSpriteOffset
tay
lda segmentScreenShifts,x
beq segmentBodyJump_noShift
@ -146,31 +172,44 @@ updateSegments_skipSpriteOffset anop
addBodySegment entry
lda numSegments
lda #SEGMENT_MAX_NUM-1
sec
sbc numSegments
asl a
tax
lda #SEGMENT_STATE_BODY
sta segmentStates,x
txa
asl a
asl a
asl a
sta segmentPosOffset,x
tay
lda #SEGMENT_DIR_LEFT
sta segmentDirections,x
lda #SEGMENT_DIR_RIGHT
sta segmentHorizontalDir,y
lda #SEGMENT_DIR_DOWN
sta segmentVerticalDir,y
lda #SEGMENT_FACING_LEFT
sta segmentFacing,x
lda #SEGMENT_FACING_RIGHT
sta segmentFacing,y
lda tileScreenOffset,x
sec
sbc #3
sta segmentScreenOffsets,x
sta segmentScreenOffsets,y
stz segmentScreenShifts,x
lda #0
sta segmentScreenShifts,y
txa
sta segmentTileOffsetsUL,x
sta segmentTileOffsetsUR,x
sta segmentTileOffsetsLL,x
sta segmentTileOffsetsLR,x
sta segmentTileOffsetsUL,y
sta segmentTileOffsetsUR,y
sta segmentTileOffsetsLL,y
sta segmentTileOffsetsLR,y
inc numSegments
@ -178,31 +217,44 @@ addBodySegment entry
addHeadSegment entry
lda numSegments
lda #SEGMENT_MAX_NUM-1
sec
sbc numSegments
asl a
tax
lda #SEGMENT_STATE_HEAD
sta segmentStates,x
lda #SEGMENT_DIR_LEFT
sta segmentDirections,x
txa
asl a
asl a
asl a
sta segmentPosOffset,x
tay
lda #SEGMENT_FACING_LEFT
sta segmentFacing,x
lda #SEGMENT_DIR_RIGHT
sta segmentHorizontalDir,y
lda #SEGMENT_DIR_DOWN
sta segmentVerticalDir,y
lda #SEGMENT_FACING_RIGHT
sta segmentFacing,y
lda tileScreenOffset,x
sec
sbc #3
sta segmentScreenOffsets,x
sta segmentScreenOffsets,y
stz segmentScreenShifts,x
lda #0
sta segmentScreenShifts,y
txa
sta segmentTileOffsetsUL,x
sta segmentTileOffsetsUR,x
sta segmentTileOffsetsLL,x
sta segmentTileOffsetsLR,x
sta segmentTileOffsetsUL,y
sta segmentTileOffsetsUR,y
sta segmentTileOffsetsLL,y
sta segmentTileOffsetsLR,y
inc numSegments
@ -216,15 +268,35 @@ shootSegment entry
numSegments dc i2'0'
; The method used to track a segments position and other details on the screen are a bit
; funky. In order to have body segments follow a head segment, we keep information from
; the position of the head segment. The segmentPosOffset gives an offset into the other
; larger arrays (97 words) which describes the position of the segment. When a head is
; updated, the segmentPosOffset is decremented. That way, the previous positions are
; still there and body segments after that can reference it.
;
; We need at least 96 of them because a slow moving head segment goes through 8 positions
; before it can be re-used by the next body segment. If there are 12 segments max, we
; need (8*12) positions to ensure all segments can know where there position was and will
; be next.
;
; But I bump that count up to 97. When the segmentPosOffset is 0, the next one to use is
; the last. It is nice to assume that the previous position information is at (index + 2).
; That works all the time except when segmentPosOffset was 0 and now wraps around to 190
; or ((96 - 1) * 2). When that happens, we copy the info from 0 to 192 or (96 *2). That
; way the code can safely assume that the old position information is in fact always at.
; (index + 2).
segmentStates dc 12i2'SEGMENT_STATE_NONE'
segmentDirections dc 12i2'SEGMENT_DIR_RIGHT'
segmentFacing dc 12i2'SEGMENT_FACING_DOWN'
segmentScreenOffsets dc 12i2'0'
segmentScreenShifts dc 12i2'0'
segmentTileOffsetsUL dc 12i2'0'
segmentTileOffsetsUR dc 12i2'0'
segmentTileOffsetsLL dc 12i2'0'
segmentTileOffsetsLR dc 12i2'0'
segmentPosOffset dc 12i2'0'
segmentHorizontalDir dc 97i2'SEGMENT_DIR_RIGHT'
segmentVerticalDir dc 97i2'SEGMENT_DIR_DOWN'
segmentFacing dc 97i2'SEGMENT_FACING_DOWN'
segmentScreenOffsets dc 97i2'0'
segmentScreenShifts dc 97i2'0'
segmentTileOffsetsUL dc 97i2'0'
segmentTileOffsetsUR dc 97i2'0'
segmentTileOffsetsLL dc 97i2'0'
segmentTileOffsetsLR dc 97i2'0'
SEGMENT_SPRITE_LAST_OFFSET gequ 7*4
segmentSpriteOffset dc i2'SEGMENT_SPRITE_LAST_OFFSET'

View File

@ -90,5 +90,31 @@ _dirtyGameTile_nonGame&SYSCNT anop
iny
sty numDirtyNonGameTiles
_dirtyGameTile_skip&SYSCNT anop
mend
macro
_dirtyGameOrNonGameTileX &tileOffset
ldy &tileOffset,x
cpy #RHS_FIRST_TILE_OFFSET
bge _dirtyGameTile_nonGame&SYSCNT
lda #TILE_STATE_DIRTY
sta tileDirty,y
bra _dirtyGameTile_skip&SYSCNT
_dirtyGameTile_nonGame&SYSCNT anop
lda tileDirty,y
bne _dirtyGameTile_skip&SYSCNT
lda #TILE_STATE_DIRTY
sta tileDirty,y
tya
ldy numDirtyNonGameTiles
sta dirtyNonGameTiles,y
iny
iny
sty numDirtyNonGameTiles
_dirtyGameTile_skip&SYSCNT anop
mend

View File

@ -8,7 +8,7 @@ s6d2 =
s7d1 = /Users/jrand/Library/Developer/Xcode/DerivedData/BuGS-bffpexoblaghkzcbtjtzxeulnuto/Build/Products/Debug/BuGS.2mg
g_limit_speed = 3
g_limit_speed = 0
bram1[00] = 00 00 00 01 00 00 0d 06 02 01 01 00 01 00 00 00