Metasprite position offsets in regards to player x and y?

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

CrowleyBluegrass
Posts: 42
Joined: Sun Jun 30, 2013 7:59 am

Metasprite position offsets in regards to player x and y?

Post by CrowleyBluegrass »

I'd just like to say thank you first for the replies to my last thread. I now understand how LOW and HIGH work, and also .dl and .dh too, and can now use them to make jump tables :) (sorry for being offtopic at the very start but didn't want to bump my previous thread)

When defining (2x2) metasprites, how do you offset them from your character x and y positions? Assuming the reference point for your player is the top left (I heard this isn't the best option but it's easier for me to comprehend than centre bottom for now) and the sprites are arranged around that point.

Do you store your metasprite data (if this is possible) as both negative and positive values? For example, the bottom-left sprite in the 2x2 arrangement would be the same x value, but of a negative y value, as it is lower than the playery value (top left corner). Right now I'm doing everything in a rather hardcoded way (for just one metapsprite) and loading the player y and x values before SBC or ADCing a fixed amount for each individual sprite in the metasprite (excepting the top left sprite) so they are arranged in a 2x2 grid.

Hope this makes sense, I don't have my (edited NN) code right now, but I'll upload it if needed. Sorry for the haphazard explanation, I am trying...

Thank you! :)
User avatar
dougeff
Posts: 3078
Joined: Fri May 08, 2015 7:17 pm

Re: Metasprite position offsets in regards to player x and y

Post by dougeff »

I've been using the NES screen tool's metasprite creator, and Shiru's neslib code to render it. I modified it slightly...

Code: Select all

_oam_meta_spr: ;changed from neslib...
;a = low byte address to metasprite
;x = high byte..
;temp = x
;temp2 = y

	sta <pointer
	stx <pointer+1
	ldx sprid
	ldy #0

@1:

	lda (pointer),y		;x offset
	cmp #$80
	beq @2
	iny
	clc
	adc <temp ;x position
	sta SPRITES+3,x
	lda (pointer),y		;y offset
	iny
	clc
	adc <temp2 ;y position
	sta SPRITES+0,x
	lda (pointer),y		;tile
	iny
	sta SPRITES+1,x
	lda (pointer),y		;attribute
	iny
	sta SPRITES+2,x
	inx
	inx
	inx
	inx
	jmp @1

@2:

	stx sprid
	rts
Here's an example of 2 metaprite definitions...
4 bytes = relative x position, relative y position, tile #, attributes
terminated with 128 ($80)

Code: Select all

Mario_Right:
.db 0, 0,$00,0
.db 8, 0,$01,0
.db 0, 8,$02,0
.db 8, 8,$03,0
.db 0,16,$04,0
.db 8,16,$05,0
.db 0,24,$06,0
.db 8,24,$07,0
.db 128

Mario_Left:
.db 8,0, $00,0|OAM_FLIP_H
.db 0,0, $01,0|OAM_FLIP_H
.db 8,8, $02,0|OAM_FLIP_H
.db 0,8, $03,0|OAM_FLIP_H
.db 8,16,$04,0|OAM_FLIP_H
.db 0,16,$05,0|OAM_FLIP_H
.db 8,24,$06,0|OAM_FLIP_H
.db 0,24,$07,0|OAM_FLIP_H
.db 128
EDIT-
so you would lda x position, sta temp, lda y position, sta temp2, lda #<Mario_Right, ldx #>Mario_Right. jsr _oam_meta_spr

sprid keeps track of the index into the sprite buffer

EDIT2 - changed slightly, haven't refined this apparently.
nesdoug.com -- blog/tutorial on programming for the NES
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Metasprite position offsets in regards to player x and y

Post by tokumaru »

I always use 4 bytes per sprite in a metasprite definition, with X and Y being signed values relative to an object's reference point, which is not fixed.

I did not use 2's complement for the coordinates though, I used something that simplified out-of-screen tests, but I can't remember what that was right now...
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Metasprite position offsets in regards to player x and y

Post by tepples »

Might it have been excess-128? The Curse of Possum Hollow uses that representation for X and Y coordinates of sprites within each metasprite.
  • (128, 128) means a sprite whose top left is at the hotspot
  • (132, 128) means a sprite whose top left is four pixels to the right of the hotspot
  • (120, 128) means a sprite whose top left is eight pixels to the left of the hotspot
  • (128, 112) means a sprite whose top left is sixteen pixels above the hotspot
Each metasprite consists of a set of horizontal strips, where each strip begins with X, Y, and attributes, followed by 1 to 8 tile numbers. The length is stored in the otherwise unused bits 4-2 of attributes, and the X position increases by 8 for each sprite in a strip.
User avatar
FrankenGraphics
Formerly WheelInventor
Posts: 2064
Joined: Thu Apr 14, 2016 2:55 am
Location: Gothenburg, Sweden
Contact:

Re: Metasprite position offsets in regards to player x and y

Post by FrankenGraphics »

In graphics and animation, the point of origin is called the anchor point (confusingly, sometimes all handles on an object are called that too but i suspect this is a mispractice).

Sprite tables can be stored as relative to that anchor point, which means that by offsetting the whole table as such, you effectively move the anchorpoint.


Examples:

Code: Select all

someMetasprite:
	.byte -8,-8,$ee,0
	.byte  0,-8,$ef,0
	.byte -8, 0,$fe,0
	.byte  0, 0,$ff,0
implies a centered anchorpoint (could work for a topdowner, but is a bit unintuitive for a platformer).

Code: Select all

someOtherMetasprite:

	.byte -8,-16,$ee,0
	.byte  0,-16,$ef,0
	.byte -8,-8,$fe,0
	.byte  0,-8,$ff,0
implies a horizontally centered, but bottom-aligned anchorpoint. Pretty convenient for sprites that ought to turn around and check against ground often.

Code: Select all

metasprite3:

	.byte   0,  0,$ee,0
	.byte   8,  0,$ef,0
	.byte   0,  8,$fe,0
	.byte   8,  8,$ff,0
implies a top- and left-aligned anchorpoint. Practical for static overlays. I guess it could be convenient in that it can actually be drawn in the top-left corner of the screen w/o wraparound as well, but the utility isn't that great imo.


When doing static overlays you want to place on an absolute position on the screen, it helps to count in powers of 8 or 16. Example:

Code: Select all

;raw OAM data
.byte (8*8)-1,$01,$00,(8*6)
the parentheses are redundant but helps me decode visually what is going on: the sprite is on the 8th row, 6th column* the -1 is likely an adjustment for the render delay. This example is strictly on the grid, but you can add offsets after the parentheses as you need.

In absolute placement, you can't use 128 as a terminator, so you need to specify an absolute length of data to be deployed in OAM this way.

*(assuming 0*8) is read as the 0th row or column.


Last note... i don't agree with NESST's choice for ordering the sprite data. It had been simpler if it was written just like how OAM is structured. It could have represented this however it is most convenient in its interface, but forcing this shuffle on the output seems unnecessary.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Metasprite position offsets in regards to player x and y

Post by tokumaru »

tepples wrote:Might it have been excess-128?
Yeah, I think this was it! I didn't even know it had a name... Still don't remember why that made things faster though, will have to check by sprite drawing code.
User avatar
gauauu
Posts: 779
Joined: Sat Jan 09, 2016 9:21 pm
Location: Central Illinois, USA
Contact:

Re: Metasprite position offsets in regards to player x and y

Post by gauauu »

tokumaru wrote:
tepples wrote:Might it have been excess-128?
Yeah, I think this was it! I didn't even know it had a name... Still don't remember why that made things faster though, will have to check by sprite drawing code.
If you dig it up, I'd be interested to learn more about it. I was just thinking last night about how to quickly handle offscreen checks for individual sprites of the metasprite, so if you have some trick you did, I'd love to hear it.
User avatar
dougeff
Posts: 3078
Joined: Fri May 08, 2015 7:17 pm

Re: Metasprite position offsets in regards to player x and y

Post by dougeff »

Last note... i don't agree with NESST's choice for ordering the sprite data. It had been simpler if it was written just like how OAM is structured. It could have represented this however it is most convenient in its interface, but forcing this shuffle on the output seems unnecessary.
I agree. I would prefer keeping the NES hardware order for the OAM data.
nesdoug.com -- blog/tutorial on programming for the NES
User avatar
Kasumi
Posts: 1293
Joined: Wed Apr 02, 2008 2:09 pm

Re: Metasprite position offsets in regards to player x and y

Post by Kasumi »

I ended up writing a program that pulled the data out of the .msp file in NESST. (Which if I remember correctly is totally the regular OAM order + 2 grid bytes at the beginning.)

For offscreen checks, I just ensured all offsets would be positive. I shift the entire metasprite's position to the max negative offset. (The program above exports that value as a constant like "ahpMETASPRITEXOFFSET = $0021")

So 0 is "the furthest left a sprite can be for this character" (-$21 for the Ahp), and everything else is to the right of that.

So to start:

Code: Select all

lda OBJxlow,x
sec
sbc #ahpMETASPRITEXOFFSET
sta tempLo

lda OBJxhigh,x
sbc #0
sta tempHi
And then the offscreen check looks like this (for X)

Code: Select all

	lda (reserved4),y;X Position
	clc
	adc tempLo
	sta OAM+3,x
	
	lda tempHi
	adc #$00
	bne spriteOffscreen
Assuming your object's anchor point and your animation's anchor point are the same, you don't even need the first step.

This may be the excess N thing, I dunno. I'm having trouble understanding the article. Will have to dedicate more time to understanding it.
Edit: I also have a max right constant exported per enemy. So if adding that number is offscreen, the entire metasprite is (for that dimension).
Last edited by Kasumi on Wed Feb 21, 2018 12:53 pm, edited 1 time in total.
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Metasprite position offsets in regards to player x and y

Post by tepples »

Yes, you are in fact using excess 33. But if you use the same excess value for all characters, your code might be simpler.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Metasprite position offsets in regards to player x and y

Post by tokumaru »

Kasumi wrote:

Code: Select all

	lda tempHi
	adc #$00
	bne spriteOffscreen
Oh yeah, I did it so the high byte of the signed coordinates is always 0! With 2's compliment it can be either $00 or $ff, so you have to sign-extend the 8-bit value of every coordinate to get that high byte. By using the excess 128 format you can just use a constant 0 as the high byte of every offset, like in the above code.
User avatar
FrankenGraphics
Formerly WheelInventor
Posts: 2064
Joined: Thu Apr 14, 2016 2:55 am
Location: Gothenburg, Sweden
Contact:

Re: Metasprite position offsets in regards to player x and y

Post by FrankenGraphics »

So.. to melt that article a bit: excess-128 is a signed 8-bit word that begins with -128 at %000000, rather than 0? And effectively the N flag would actually represent a positive (starting at %100000 and onwards), rather than a negative when excess-128 is used on a system meant for two's complement.

I have a bit of trouble understanding how you even use excess-128 to represent something to begin with if that's not the native system. :oops:
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Metasprite position offsets in regards to player x and y

Post by tokumaru »

FrankenGraphics wrote:So.. to melt that article a bit: excess-128 is a signed 8-bit word that begins with -128 at %000000, rather than 0?
Yeah, $00 representss -128, $80 represents 0, $ff represents 127. The most important aspect of this is that the high byte is always 0, even for negative values, unlike in 2's complement.
And effectively the N flag would actually represent a positive (starting at %100000 and onwards), rather than a negative when excess-128 is used on a system meant for two's complement.
Yeah, but at least the N flag is still usable, just with its meaning inverted. Not that we need it in this particular case, though.
I have a bit of trouble understanding how you even use excess-128 to represent something to begin with if that's not the native system. :oops:
Different systems always need some sort of conversion, no way around that I guess... To make the excess-128 offsets work, the reference coordinate for sprites needs to have 128 subtracted from it beforehand, so that when excess-128 values are added later, the results are valid 2's complement values. You effectively trade all the sign extensions you'd need for that one subtraction in the beginning.

EDIT: Typos.
Last edited by tokumaru on Wed Feb 21, 2018 9:38 pm, edited 1 time in total.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Metasprite position offsets in regards to player x and y

Post by tokumaru »

I know that not many of you are familiar with Atari 2600 development, but in my case, this excess-128 thing for sprites works a bit like the horizontal positioning of sprites in that console.

The 2600 has a very rudimentary video chip (the TIA) with a small number of movable objects, and you don't have direct access to their on-screen coordinates. To position sprites you need to use timed code and "reset" their positions at the exact moment in the scanline where you want them to appear. The CPU runs 3 times slower than the TIA, so you can't really position objects with pixel-perfect precision. For these precise pixel adjustments, the TIA can be told to move sprites left or right using separate signed 4-bit offsets for each object. This is not what happens internally, though: In reality, the 4-bit offsets can only move sprites 0 to 15 pixels to the left. To make it seem like you can move sprites left and right, the TIA simply moves all objects 8 pixels to the right before applying the offsets, giving the final range of -7 to +8 pixels.

I do exactly the same when drawing metasprites on the NES. I want to use positive coordinates only for the individual sprite offsets (so that the implicit high byte is always 0), meaning that I can only put sprites 0 to 255 pixels to the right of an object's reference point. That's no good, since I absolutely need to put sprites to the left of the reference point too, so I essentially "cheat" and move the reference point 128 pixels back, so my effective range becomes -128 to 127 pixels, but using only "positive" offsets.

I hope this makes sense!
User avatar
FrankenGraphics
Formerly WheelInventor
Posts: 2064
Joined: Thu Apr 14, 2016 2:55 am
Location: Gothenburg, Sweden
Contact:

Re: Metasprite position offsets in regards to player x and y

Post by FrankenGraphics »

The 2600 example made perfect sense! :beer: :D

But wouldn't it suffice to assume that while on-screen, the high byte is 0? If moving out of bounds to the left or up, decrease, get $ff (ie non-zero), if out of bounds to the right or down, increase, get $1 (also nonzero), from where you can beq past routines for checking if the entity should be inactivated/decrease its update rate/"hide" its representation contents by moving the sprites to an unseen lower position.


edit: fixed mixup of directions.
Last edited by FrankenGraphics on Wed Feb 21, 2018 4:15 pm, edited 1 time in total.
Post Reply