Jump to content



0

Positioning p0 sprite horizontally according to variable (0-150)?


7 replies to this topic

#1 Propane13 ONLINE  

Propane13

    Stargunner

  • 1,385 posts
  • Location:Philly

Posted Fri May 2, 2008 8:21 AM

Hi everybody,

I thought this would be a good question to post in the newbie forum.
I am aware of an algorithm that Joe Decuir wrote up "back in the day" (I believe for Combat), where you could take a value between say, 1 and 150, and based on that value, set RESP0 and HMP0 appropriately. However, if I remember right, this position algorithm happens during VBLANK. I need something like this to happen during the kernel.

So, I'm looking for a routine that say... in 2-3 scanlines during the kernel does the calculations based on a horizontal position variable in Ram.
Does anyone have any code like this that they would be willing to share?

For new programmers, this is useful code for the case that you have multiple things going on in the kernel (say, at the top of the screen you use P0 for a score, at the middle, you use P0 as a character that can move left and right on the screen, and at the bottom of the screen, you have a "lives" counter).

Regards,
-John

#2 vdub_bobby OFFLINE  

vdub_bobby

    Quadrunner

  • 5,831 posts
  • Boom bam.
  • Location:Seattle, WA

Posted Fri May 2, 2008 3:37 PM

Here's my version, starting with horizontal position in A and sprite number (0 = P0, 1 = P1, 2 = M0, etc.) in X:
   sec
   sta HMCLR
   sta WSYNC
DivideLoop
   sbc #15
   bcs DivideLoop
   eor #7
   asl
   asl
   asl
   asl
   sta.wx HMP0,X
   sta RESP0,X
   sta WSYNC
   sta HMOVE
This will run in constant time, which is almost necessary for in-kernal use. Starting after the first STA WSYNC, it will end exactly 79 cycles later for all horizontal positions <= 160. Plus it's general, compact, and very easy to use. I've use this routine, or variations, in every 2600 program I've written. ;)

There is also a table version, something like this:
   sta WSYNC
   sec
   sta HMCLR
DivideLoop
   sbc #15
   bcs DivideLoop
   tay
   lda HMPxTable,Y;not crossing page boundary
   sta HMP0,X
   sta RESP0,X
   sta WSYNC
   sta HMOVE
You have to set up the table carefully so that either you always cross a page boundary when you read it or so that you never do (since Y will hold -1 through -15).

Just make sure that the STA RESP0,X instruction ends at cycle 23 when the BCS branch is not taken (i.e., the horizontal position < 15) for the timing to work.

Edited by vdub_bobby, Fri May 2, 2008 3:40 PM.


#3 Propane13 ONLINE  

Propane13

    Stargunner

  • 1,385 posts
  • Location:Philly

Posted Mon May 5, 2008 7:12 AM

This code works perfectly, and is more efficient than I realized you could possibly get (I was expecting 3 scanlines, not less).
Thank you for sharing!

-John

#4 SpiceWare OFFLINE  

SpiceWare

    Quadrunner

  • 5,987 posts
  • Medieval Mayhem
  • Location:Planet Houston

Posted Mon May 5, 2008 10:29 AM

I used a variation of this in Stay Frosty so that Frosty's sprite and color could still be updated on scan lines that the fireballs were positioned on. There is a tradeoff, the X range is 4-147. The range can be expanded if only the sprite(and not the color) is updated, but for Stay Frosty it didn't matter as the platforms are only drawn using PF1 and PF2, so the fireballs couldn't travel that afar (well, they could on the bottom level).

PosPlayer1:	  ; A holds X position for player 1
		sec	  ; X holds GRP0
		sta WSYNC; Y holds COLUP0
		stx GRP0	 ; 3
		sty COLUP0; 3	6
DivideLoop1:
		sbc #15	  ; 2	8
		bcs DivideLoop1; 2   10
		eor #7	; 2   12
		asl		  ; 2   14
		asl		  ; 2   16
		asl		  ; 2   18
		asl		  ; 2   20
		sta RESP1	; 2   23 <- set object position
		sta HMP1	 ; 3   26
		sta WSYNC
		sta HMOVE
		rts

Edited by SpiceWare, Mon May 5, 2008 10:30 AM.


#5 vdub_bobby OFFLINE  

vdub_bobby

    Quadrunner

  • 5,831 posts
  • Boom bam.
  • Location:Seattle, WA

Posted Mon May 5, 2008 11:51 AM

Since you weren't using Y as a scanline counter - at least for that line - you could have saved a few cycles by using the table method I posted above (at the expense of a 15-byte table). Could have an X-range of 4-159. Of course, if you don't need the range, no point in changing what works. ;)

#6 SpiceWare OFFLINE  

SpiceWare

    Quadrunner

  • 5,987 posts
  • Medieval Mayhem
  • Location:Planet Houston

Posted Mon May 5, 2008 1:18 PM

I'll have to remember that for next time :thumbsup:

#7 Wickeycolumbus OFFLINE  

Wickeycolumbus

    River Patroller

  • 4,063 posts
  • Location:Michigan

Posted Sat May 24, 2008 7:31 PM

I still don't get this code. Can someone help me? I posted my code.

	processor 6502
	include "vcs.h"
	include "macro.h"
	org $F000



START
	CLEAN_START

	lda #$FF
	sta GRP0
	lda #$F0
	sta COLUP0
	

STARTFRAME

	lda #0
	sta VBLANK
	
	lda #2
	sta VSYNC

	sta WSYNC
	sta WSYNC
	sta WSYNC
	
	lda #0
	sta VSYNC

	ldy #37
	ldx #0
	lda #0
VERT
	sta WSYNC

			
 	sec
   	sta HMCLR
   	sta WSYNC
DivideLoop
   	sbc #15
   	bcs DivideLoop
   	eor #7
   	asl
   	asl
   	asl
   	asl
   	sta.wx HMP0,X
   	sta RESP0,X
   	sta WSYNC
   	sta HMOVE

	dey
	bne VERT

	ldy #192

picture
	sta WSYNC



	dey
	bne picture

	ldy #30
over
	dey
	sta WSYNC
	bne over



	jmp STARTFRAME








	org $FFFA
	.word START
	.word START
	.word START

Edited by Wickeycolumbus, Sat May 24, 2008 8:38 PM.


#8 supercat OFFLINE  

supercat

    Quadrunner

  • 6,367 posts

Posted Sat May 24, 2008 9:43 PM

View PostSpiceWare, on Mon May 5, 2008 10:29 AM, said:

I used a variation of this in Stay Frosty so that Frosty's sprite and color could still be updated on scan lines that the fireballs were positioned on.

One approach you could use if you want to 'do stuff' on scan lines where you perform horizontal positioning would be to execute different routines when the object to be places is near the right of the screen than when it's near the left; in the former scenario, you'll have time to do stuff after the RESPX; in the latter scenario you'll have time before. Two caveats with this approach:

-1- You'll probably end up updating a sprite mid-line. Provided you have a choice of two times at least three cycles apart where the update can take place, this needn't pose a problem; simply use whichever one won't overlap the display of the sprite, and adjust the position up or down a scan line based upon whether your update happens before or after the sprite.

-2- Although this approach could be used to maintain a full-width non-symmetric playfield (using non-reflected mode), hitting PF2 at the right cycle for using reflected mode would mean that certain sprite positions could not be reached with a single HMOVE.

Still, the approach would offer the ability to offer some nice flexibility in a game with mid-frame horizontal repositioning.




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users