Metasprite position offsets in regards to player x and y?
Moderator: Moderators
-
- Posts: 42
- Joined: Sun Jun 30, 2013 7:59 am
Metasprite position offsets in regards to player x and y?
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!
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!
Re: Metasprite position offsets in regards to player x and y
I've been using the NES screen tool's metasprite creator, and Shiru's neslib code to render it. I modified it slightly...
Here's an example of 2 metaprite definitions...
4 bytes = relative x position, relative y position, tile #, attributes
terminated with 128 ($80)
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.
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
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
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
Re: Metasprite position offsets in regards to player x and y
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...
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...
Re: Metasprite position offsets in regards to player x and y
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
- 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
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:
implies a centered anchorpoint (could work for a topdowner, but is a bit unintuitive for a platformer).
implies a horizontally centered, but bottom-aligned anchorpoint. Pretty convenient for sprites that ought to turn around and check against ground often.
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:
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.
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
Code: Select all
someOtherMetasprite:
.byte -8,-16,$ee,0
.byte 0,-16,$ef,0
.byte -8,-8,$fe,0
.byte 0,-8,$ff,0
Code: Select all
metasprite3:
.byte 0, 0,$ee,0
.byte 8, 0,$ef,0
.byte 0, 8,$fe,0
.byte 8, 8,$ff,0
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)
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.
Re: Metasprite position offsets in regards to player x and y
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.tepples wrote:Might it have been excess-128?
Re: Metasprite position offsets in regards to player x and y
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.tokumaru wrote: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.tepples wrote:Might it have been excess-128?
My games: http://www.bitethechili.com
Re: Metasprite position offsets in regards to player x and y
I agree. I would prefer keeping the NES hardware order for the OAM data.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.
nesdoug.com -- blog/tutorial on programming for the NES
Re: Metasprite position offsets in regards to player x and y
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:
And then the offscreen check looks like this (for X)
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).
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
Code: Select all
lda (reserved4),y;X Position
clc
adc tempLo
sta OAM+3,x
lda tempHi
adc #$00
bne spriteOffscreen
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.
Re: Metasprite position offsets in regards to player x and y
Yes, you are in fact using excess 33. But if you use the same excess value for all characters, your code might be simpler.
Re: Metasprite position offsets in regards to player x and y
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.Kasumi wrote:Code: Select all
lda tempHi adc #$00 bne spriteOffscreen
- 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
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.
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.
Re: Metasprite position offsets in regards to player x and y
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.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, but at least the N flag is still usable, just with its meaning inverted. Not that we need it in this particular case, though.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.
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.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.
EDIT: Typos.
Last edited by tokumaru on Wed Feb 21, 2018 9:38 pm, edited 1 time in total.
Re: Metasprite position offsets in regards to player x and y
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!
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!
- 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
The 2600 example made perfect sense!
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.
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.