tschak909 Posted June 1, 2006 Share Posted June 1, 2006 In the book De Re Atari, Chris Crawford talks about moving the player vertically through memory. It's very straightforward... VERTICAL MOTION Animating this image is very easy. Vertical motion is obtained by moving the image data through the player RAM. This is, in principle, the same method used in playfield animation, but there is a big difference in practice; the move routine for vertical motion is a one-dimensional move instead of a two-dimensional move. The program does not need to multiply by 40 and it often does not need to use indirection. It could be as simple as: LDX $01 LOOP LDA PLAYER,X STA PLAYER-1,X INX BNE LOOP This routine takes about 4 milliseconds to move the entire player, about half as long as the playfield animation routine which actually moves only 50 bytes where this one moves 256 bytes. If high speed is necessary, the loop can be trimmed to move only the image bytes themselves rather than the whole player; then the loop would easily run in about 100-200 microseconds. The point here is that vertical motion with players is both simpler and faster than motion with playfield objects. of special note, is that next to last sentence in the paragraph. If high speed is necessary, the loop can be trimmed to move only the image bytes themselves rather than the whole player; then the loop would easily run in about 100-200 microseconds. What is he talking about there? -Thom Quote Link to comment Share on other sites More sharing options...
Rybags Posted June 1, 2006 Share Posted June 1, 2006 (edited) Presumably, that example should read LDX #$01, not LDX $01. In such case, then 255 bytes are moved, which is very time consuming especially if it's just a 16 pixel high sprite. Moving just the image bytes, you use an index for the YPOS of the sprite, then another to access the original data. Or, better still - just use the one register and use self-modifying code: LDA SPRITE_YPOS STA PLR0ADR LDX #SPRITE_HEIGHT; number of pixels (-1) height of player LOOP: LDA SPRITE_DATA,X PLR0ADR=*+1 STA $4C00,X DEX BPL LOOP Note: PLR0ADR should be the address of the operand of the STA instruction - some assemblers will need adjustment on the "*+1" equate. The only problem with that method is that you are not erasing the previous rendition of the sprite - extra logic is needed. One method is to keep track of the previous YPOS of the sprite. Then, compare the new vs old YPOS. If it is > oldY, then you will need to store zeros from the oldY to currentY (-1). If it is equal, you don't need to do anything (in fact, you don't even need to draw the sprite). If it is < oldY, then you need to store zeros from the end of the sprite (+1) to the end of the old sprite. I use that method in my Impossible Mission routine (see av.) - it's well suited since I'm animating 3 Players to generate 1 sprite, and they all have a similar Y position. If it's the case that you're only moving one player and it's not very tall, and doesn't move much between renders, then it would probably be quicker to just unconditionally write several zeros before and after the sprite. You can even have your sprite defined with zeros packed either side. Another alternative is to just erase the sprite between rendering them... which is fine if it's not a tall sprite too. Edited June 1, 2006 by Rybags Quote Link to comment Share on other sites More sharing options...
Heaven/TQA Posted June 1, 2006 Share Posted June 1, 2006 the de re atari routine is not very usable for a game imho... in venus/boinxx i use a similar method rybags describes... and you can avoid the erasing of the player data while repositioning with the extra 0 on top and below the actual sprite data... why the hell do we not have "real" sprites.... Quote Link to comment Share on other sites More sharing options...
tschak909 Posted June 1, 2006 Author Share Posted June 1, 2006 well, see.. I do understand that the atari 800 method for rendering "players" and "missiles" is a direct evolution of the way it's done in the 2600.. Instead of a kernel shoving bits into the TIA's registers at just the right time, we've got ANTIC shoving the bits in there for us, given that the Atari 800's design started almost immediately after the finishing of the 2600's design, this does make sense... all the same, I do share your frustration. Ultimately i am trying to figure out how to eventually handle multiple incarnations of an enemy player on the screen in "R-Type" like patterns, while using maybe two players for the main ship.... -Thom Quote Link to comment Share on other sites More sharing options...
Rybags Posted June 1, 2006 Share Posted June 1, 2006 You might (if you can follow it) get something useful out of this. It is the sprite routine for IM. For the sprite, I only keep 1 copy - since there are about 27 animation frames x 3 players. The right side of the man is stored facing the other way - I use a table which the init routine generates to "flip" the data when needed so that it faces the desired way. The routine has the logic needed to erase what's needed without extra unnecessary stores - I only did it this way as it saves time, since it's doing 3 player renders at a time. Code is a bit messy and some comments are wrong, but it works: *=$5800 pxpos = $630; xpos of player pypos = $631; ypos of player (bottom) spritep = $632; sprite # (0-27) oldpypos = $633; previous ypos of player (bottom) pystart = $634; ypos of player (top) oldpystart = $635; previous ypos of player (top) p0pointer = $e0; indirect - point to sprite data p1pointer = $e2 p2pointer = $e4 plrheight = $e6; height of player ycount = $e7; counter (from plrheight) plrend = $e7; index into players for 2nd clear operation ztemp1 = $e7; temp store for init ; jmp draw_player jmp init draw_player pla; for BASIC only wait1 lda $d40b cmp #8 bne wait1 lda #4 sta 77; kill attract mode sta $d01a lda pxpos sta $d000 clc adc #8 sta $d001 lda spritep php; save N flag for direction and #$1f tay lda playerl,y sta p0pointer; address of sprite data lda playerh,y sta p0pointer+1 sta p1pointer+1 sta p2pointer+1 lda plrheighttab,y; player height tax stx plrheight; height of player (-1) stx ycount; counter sec adc p0pointer sta p1pointer bcc noinc1 inc p1pointer+1 inc p2pointer+1 noinc1 sec adc plrheight sta p2pointer bcc noinc2 inc p2pointer+1 noinc2 lda pypos sec sbc plrheight sbc yoffset,y; y offset for each ani frame sta pystart sta storep0+1 sta storep1+1 sta storep2+1 sta storep0a+1 sta storep1a+1 sta storep2a+1 sec adc plrheight sta plrend; end of player index (+1) for 2nd clear op lda #0 ldx oldpystart zero sta $7c00,x sta $7d00,x sta $7e00,x inx cpx pystart bcc zero ldy plrheight plp; check n flag from before bmi backwards; do move for facing backwards ; ; store sprite facing forwards ; forwards lda (p0pointer),y storep0 sta $7c00,y; left side lda (p1pointer),y tax lda fliptable,x storep1 sta $7d00,y; right side - player 1 lda (p2pointer),y storep2 sta $7e00,y; arms/head - plr 2 dey bpl forwards lda pxpos ldy spritep clc adc xadjust,y sta $d002 wipe_old lda #0 ldx plrend zero2 sta $7c00,x sta $7d00,x sta $7e00,x cpx oldpypos bcs finished inx bne zero2 ; ; store sprite facing backwards ; backwards lda (p0pointer),y tax lda fliptable,x storep0a sta $7d00,y; right side -plr 1 lda (p1pointer),y storep1a sta $7c00,y; left side - plr 1 lda (p2pointer),y tax lda fliptable,x storep2a sta $7e00,y; arms/head - player 2 dey bpl backwards lda spritep and #$1f tay lda pxpos clc adc xadjustb,y sta $d002 jmp wipe_old finished lda pypos sta oldpypos lda pystart sta oldpystart lda $2c8 sta $d01a rts ; ; inititalize - generate "flip" table, set various variables ; init pla ldx #0 dotable txa and #$f tay lda fliplow,y asl a asl a asl a asl a sta ztemp1 txa lsr lsr lsr lsr tay lda fliplow,y ora ztemp1 sta fliptable,x inx bne dotable stx oldpystart dex stx oldpypos rts ; x adjustment for player 2 (white part) xadjust .byte 4,4,4,4,4,4,4,4,4,4 .byte 4,4,4,4,4,4,4,4,4,4 .byte 4,4,4,1,4,4,4,4,4,4 .byte 4,4 xadjustb .byte 4,4,4,4,4,4,4,4,4,4 .byte 4,4,4,4,4,4,4,4,4,4 .byte 4,4,4,7,4,4,4,4,4,4 .byte 4,4 ; y offset for each animation frame yoffset .byte 0,0,0,0,2,2,1,0,0,0 .byte 0,2,2,1,0 .byte 1,5,13,21 .byte 22,24,26,25,23,16,4,0,0 .byte 0,0,0,0,0; filler fliplow .byte $00,$08,$04,$0c .byte $02,$0a,$06,$0e .byte $01,$09,$05,$0d .byte $03,$0b,$07,$0f ; set org to page boundary neworg .=(*+$100)&$ff00 *=neworg fliptable *=*+$100 playerl .ds 1 *=*+31 playerh .ds 1 *=*+31 plrheighttab .ds 1 *=*+31 Quote Link to comment Share on other sites More sharing options...
Wrathchild Posted June 1, 2006 Share Posted June 1, 2006 The Players and Missiles don't necessarily require DMA to be displayed, you can directly pump values into the data register, e.g. in a DLI or by writing your own kernel. So that would be more like doing things in 2600 style. Check this thread for an example: http://www.atariage.com/forums/index.php?s...=0entry686352 (Really, I should go back and complete this port!) Quote Link to comment Share on other sites More sharing options...
tschak909 Posted June 1, 2006 Author Share Posted June 1, 2006 I am familiar with that particular technique as well, that is how Atari Basketball works, primarily so that it was possible to get that much colour on screen at once. -Thom Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.