SNES Programing Help 2
Moderator: Moderators
Forum rules
- For making cartridges of your Super NES games, see Reproduction.
Re: SNES Programing Help 2
But then you create a lot of other problems in the code as you need to account for the wrapping.
It'd be probably better to store coordinates as 16-bit integer (no fractional part) and speeds as 8.8 fixed point, then when applying the momentum fake the subpixel accuracy through dithering over time.
It'd be probably better to store coordinates as 16-bit integer (no fractional part) and speeds as 8.8 fixed point, then when applying the momentum fake the subpixel accuracy through dithering over time.
-
psycopathicteen
- Posts: 3001
- Joined: Wed May 19, 2010 6:12 pm
Re: SNES Programing Help 2
I guess it depends how much continuity you want. If you're okay with objects resetting themselves, or doing one way scrolling, you could do it this way, but if you need to come back to objects later, then it doesn't work as well.
- Drew Sebastino
- Formerly Espozo
- Posts: 3496
- Joined: Mon Sep 15, 2014 4:35 pm
- Location: Richmond, Virginia
Re: SNES Programing Help 2
Okay, you know, I tried to start working on using direct page, but just after writing
It glitched up, and I didn't even write lda.b for anything yet, so I don't get it. I have two files, one called Metasprite and Metasprite Bad. (The sprite flipping isn't completed yet, so it looks really weird, but that isn't the problem.) Metasprite Bad is obviously the one that causes it to get jacked up. (It works fine until a bullet gets spawned by pressing B.) Game is using Metasprite, while Game Bad is using Metasprite Bad. I really don't have a clue what the problem is, because I've never done anything with direct page. I'd say look at bullet in Objects, and see Metasprite Bad.
Code: Select all
lda ObjectOffset ;make sure you're in 16-bit A mode
tcd ;set direct page (D) register to address of current object slotRe: SNES Programing Help 2
I was actually thinking more about what would happen when a moving object crosses a boundary (which will inevitably happen).psycopathicteen wrote:I guess it depends how much continuity you want. If you're okay with objects resetting themselves, or doing one way scrolling, you could do it this way, but if you need to come back to objects later, then it doesn't work as well.
Re: SNES Programing Help 2
Okay, I have to leave for the weekend here and I'm not sure I have either the time or motivation to go through your code and actually find your problem for you, but I do have some suggestions:Espozo wrote:Okay, you know, I tried to start working on using direct page, but just after writing
It glitched up, and I didn't even write lda.b for anything yet, so I don't get it. I have two files, one called Metasprite and Metasprite Bad. (The sprite flipping isn't completed yet, so it looks really weird, but that isn't the problem.) Metasprite Bad is obviously the one that causes it to get jacked up. (It works fine until a bullet gets spawned by pressing B.) Game is using Metasprite, while Game Bad is using Metasprite Bad. I really don't have a clue what the problem is, because I've never done anything with direct page. I'd say look at bullet in Objects, and see Metasprite Bad.Code: Select all
lda ObjectOffset ;make sure you're in 16-bit A mode tcd ;set direct page (D) register to address of current object slot
When you start using Direct Page for the first time, it will probably cause a bunch of problems if your assembler is anything like WLA. I don't know if that's the case, but with WLA, I had to add a ".b" on every single instruction referencing an address less than $0100, because WLA just assumed that a LDA $0050 meant LDA $50 from direct page. If you have ANY other instructions anywhere in your code that are being interpreted as a direct-page instruction incorrectly, they would have worked just fine before but will screw things up now that you start moving the direct page register. That might not be a problem for you in ca65.
So what to do? Very first idea is simply preserve the D register before and after your object routine. If you PHD at the very beginning of it, and PLD at the end, then whatever you do inside the routine the D register will be restored (presumably to 0000) by the end and stop screwing up the rest of your code. You can tighten this up to just one instruction for testing. Say,
phd
lda objectOffset
tcd
lda.b objectXPosition
pld
And then see if that one lda.b instruction was being carried out correctly. If you can get one to work you can get them all to work.
FFFFFFFFFFFF OH WAIT I JUST REMEMBERED doesn't ca65 have some kind of CRIPPLING bug with direct page where you have to compensate for how stupidly it interprets it? I completely forgot about that and I virtually guarantee there's your problem. I'm afraid you'll have to ask somebody who actually uses ca65 about that...
Re: SNES Programing Help 2
In ca65, you can use direct page addressing for any instruction that supports it with the < (low byte) operator. You just have to watch out for instructions that don't support direct page addressing, such as d,y (direct page indexed with Y) with anything other than STX or LDX.
Code: Select all
phd
lda objectOffset
tcd
lda <objectXPosition
pld
- Drew Sebastino
- Formerly Espozo
- Posts: 3496
- Joined: Mon Sep 15, 2014 4:35 pm
- Location: Richmond, Virginia
Re: SNES Programing Help 2
Yeah, that fixed it. (I haven't actually tried using it yet, I'm just saying I put it in and the game acts normally.) The thing is though, every time I want to load something using direct page, I have to use phd and pld? Isn't that not very efficient? I look at the object's x position, y position, and the several tile numbers for each sprite on a loop, all using direct page, so that's a problem.tepples wrote:In ca65, you can use direct page addressing for any instruction that supports it with the < (low byte) operator. You just have to watch out for instructions that don't support direct page addressing, such as d,y (direct page indexed with Y) with anything other than STX or LDX.Code: Select all
phd lda objectOffset tcd lda <objectXPosition pld
Re: SNES Programing Help 2
You only have to push and pull D if you're returning to a routine that expects D not to have changed. And even then, you only need to push at the start and pull at the end.
Thus D is really just another indexing register. But if you're using D as the base pointer for an index into an array of structures in this manner, and you want to access variables in your actual zero page inside this loop, you'll need to make sure to use absolute mode (in ca65, a:some_label) or absolute long mode (f:some_label) for those variables, depending on where the data bank register B points.
Code: Select all
phd
lda #0
loop:
tcd
; OMITTED: bunch of stuff
tdc
clc
adc #SIZEOF_OBJECT
cmp #SIZEOF_OBJECT * MAX_OBJECTS
bcc loop
pld
Re: SNES Programing Help 2
I don't know if it qualifies as either crippling or a bug, but you do apparently have to pay attention because the memory segment feature is 6502-centric and only knows about zero page.Khaz wrote:doesn't ca65 have some kind of CRIPPLING bug with direct page
- Drew Sebastino
- Formerly Espozo
- Posts: 3496
- Joined: Mon Sep 15, 2014 4:35 pm
- Location: Richmond, Virginia
Re: SNES Programing Help 2
Ugg, Good Lord, what's wrong now? I tried to make object x and y positions use direct page, but it appears direct page is being loaded from the wrong location or something, because the values are 0 when they shouldn't be. There is now Game Bad or anything, I just have it to where Metasprite the sfc file is the messed up ones. Bullets don't spawn for some reason. (The code pretty much follows the players in terms of how it's set up, so I have no idea.)
(Random, but I can't help but find the opcode phd a little funny.)
(Random, but I can't help but find the opcode phd a little funny.)
- Drew Sebastino
- Formerly Espozo
- Posts: 3496
- Joined: Mon Sep 15, 2014 4:35 pm
- Location: Richmond, Virginia
Re: SNES Programing Help 2
Wait, I looked at my code and it makes no sense. Just to get this straight, does direct page act exactly like x and y? I adjusted my code to where I wrote
and did
Later and it still doesn't work. (Man, why isn't there just a "z".
) I think I sort of know the reason only the player had worked and not the bullets though. The player is the first object.
Seriously, what is wrong with this?
Code: Select all
lda ObjectOffset
tcdCode: Select all
adc <ObjectTable+YPositionSeriously, what is wrong with this?
Code: Select all
.setcpu "65816"
.smart
; See Game.asm
.importzp Empty
.importzp MetaspriteTableOffset
.importzp MetaspriteDirection
.importzp MetaspritePalette
.importzp MetaspriteCharacterOffset
.importzp MetaspriteCount
.importzp HFlipMask
.importzp VFlipMask
.importzp SpriteCount
.importzp ObjectOffset
.import SpriteBuf1
.import SpriteBuf3
.import MetaspriteTable
.import ObjectTable
Identity = 0
XPosition = 2
YPosition = 4
XVelocity = 6
YVelocity = 8
Atributes = 10
; Used by Game.asm
.export start_metasprite
.segment "CODE"
;
; start_metasprite
;
; Upon entry:
; X register = offset into MetaspriteTable to start at
; Y register = offset to start writing at in SpriteBuf1
;
.proc start_metasprite
phd
rep #$30 ; A=16, X/Y=16
ldy SpriteCount
ldx MetaspriteTableOffset
lda ObjectOffset
tcd
stz HFlipMask
lda MetaspriteDirection
bit #$0001
beq metasprite_loop
lda #$FFFF
sta HFlipMask
metasprite_loop:
cpy #$0200 ; sees if all 128 sprites are used up
beq done
and #$00FF
sta SpriteBuf1+1,y ; Store sprite Y position in SpriteBuf1+1,y
lda MetaspriteCount ; If MetaspriteCount is zero, then we're done. Otherwise we have
beq done ; metasprites to iterate over and populate for DMA (see VBlank)
lda Empty,x ; 1st byte = sprite X position (value 0-255)
eor HFlipMask
clc
adc <ObjectTable+XPosition
cmp #256
bcc sprite_x_not_out_of_bounds
cmp #65504
bcs sprite_x_not_out_of_bounds
bra sprite_out_of_bounds
sprite_x_not_out_of_bounds:
and #$01FF
sta SpriteBuf3,y ; Store sprite X position SpriteBuf1+y
and #$00FF
sta SpriteBuf1,y ; Store sprite X position SpriteBuf1+y
lda Empty+2,x ; 1st byte = sprite X position (value 0-255)
eor VFlipMask
clc
adc <ObjectTable+YPosition
cmp #224
bcc sprite_y_not_out_of_bounds
cmp #65504
bcs sprite_y_not_out_of_bounds
bra sprite_out_of_bounds
sprite_y_not_out_of_bounds:
sta SpriteBuf1+1,y
lda Empty+4,x
sta SpriteBuf3+2,y ; Sprite size
lda Empty+6,x
clc
adc MetaspritePalette
clc
adc MetaspriteCharacterOffset
sta SpriteBuf1+2,y ; Palette/Character word
txa
clc
adc #$0008
tax
iny
iny
iny
iny
dec MetaspriteCount ; Decrement MetaspriteCount by 1
bra metasprite_loop ; Back to the loop...
sprite_out_of_bounds:
txa
clc
adc #$0008
tax
dec MetaspriteCount ; Decrement MetaspriteCount by 1
bra metasprite_loop ; Back to the loop...
done:
sty SpriteCount ; Says how many sprites have been made
pld
rts
.endproc-
UnDisbeliever
- Posts: 77
- Joined: Mon Mar 02, 2015 1:11 am
- Location: Australia (PAL)
- Contact:
Re: SNES Programing Help 2
ca65 uses 1 byte addressing (direct page) if either:Khaz wrote:FFFFFFFFFFFF OH WAIT I JUST REMEMBERED doesn't ca65 have some kind of CRIPPLING bug with direct page where you have to compensate for how stupidly it interprets it? I completely forgot about that and I virtually guarantee there's your problem. I'm afraid you'll have to ask somebody who actually uses ca65 about that...
- The address is a zeropage variable (in a .zeropage segment or marked zp with .globalzp or .importzp), or
- .lobyte or < function is used, or
- The variable is a constant and < $100, or
- The variable is part of a struct and its address is < $100
What I do is define all of an object's variables in a struct
Header:
Code: Select all
.struct NpcStruct
state .addr
xPos .res 3
yPos .res 3
; ... etc ...
.endstruct
N_NPCS = 12
.global npcs
.segment "SHADOW"
npcs: .res .sizeof(NpcStruct) * N_NPCS
And access the fields through the struct, because they resolve to a constant < $100 they are in DP.
Code: Select all
; DP = a NpcStruct object
LDX NpcStruct::state
LDA NpcStruct::xPos + 2
BMI NegativeX
; ... etc ...
Also writing up a game loop
Code: Select all
ProcessNpcs:
PHD
REP #$30
.A16
.I16
LDA #npcs
@Loop:
TCD
LDX NpcStruct::state
BEQ @Skip
; code to process NPCs
@Skip:
TDC
ADD #.sizeof(NpcStruct)
CMP #npcs + N_NPCS * .sizeof(NpcStruct)
BLT @Loop
PLD
RTS
I think your problem is that your trying to access the Metasprite* variables (by .importzp) and the objects as a 1 byte address at the same time. When you set the DP register all 1 byte addresses will be added to DP to form the effective address.Espozo wrote:Wait, I looked at my code and it makes no sense. Just to get this straight, does direct page act exactly like x and y? I adjusted my code to where I wrote
and didCode: Select all
lda ObjectOffset tcd
Later and it still doesn't work. (Man, why isn't there just a "z".Code: Select all
adc <ObjectTable+YPosition) I think I sort of know the reason only the player had worked and not the bullets though. The player is the first object.
Seriously, what is wrong with this?
Secondly, the value of ObjectTableis $0620 according to map.txt. Masking it to a 1 byte addresses will not work as you anticipate. What I think you are after is adc <YPosition after setting DP to #ObjectTable.
Lastly, by running the code through a trace logger it appears the value of ObjectOffset is 0, not $0620 (#ObjectTable) so there isn't any DP offsetting anyway.
- Drew Sebastino
- Formerly Espozo
- Posts: 3496
- Joined: Mon Sep 15, 2014 4:35 pm
- Location: Richmond, Virginia
Re: SNES Programing Help 2
What?UnDisbeliever wrote:I think your problem is that your trying to access the Metasprite* variables (by .importzp) and the objects as a 1 byte address at the same time. When you set the DP register all 1 byte addresses will be added to DP to form the effective address.
Again, what?UnDisbeliever wrote:Secondly, the value of ObjectTableis $0620 according to map.txt. Masking it to a 1 byte addresses will not work as you anticipate. What I think you are after is adc <YPosition after setting DP to #ObjectTable.
If you're looking at the first code, I severely jacked it up. #ObjectTable is the offset of where the object table starts, and ObjectOffset is the offset that says what object we're on in the object table. (Sorry if the names weren't very clear...) Should I doUnDisbeliever wrote:Lastly, by running the code through a trace logger it appears the value of ObjectOffset is 0, not $0620 (#ObjectTable) so there isn't any DP offsetting anyway.
Code: Select all
lda #ObjectTable
clc
adc ObjectOffset
tcdCode: Select all
adc <YPositionEdit: I tried what I just suggested, and it still doesn't work.
I guess it still doesn't work because of problems #1 and #2 you said?
Re: SNES Programing Help 2
It might be easier to understand with a concrete example. Assume D = $0880 and the CPU is executing the instruction adc $23. The "1-byte address" is $23. The CPU adds the value 35 ($23) to the current value of D ($0880), producing $08A3, and then uses $0008A3 as the address of the operand of adc.Espozo wrote:What?UnDisbeliever wrote:I think your problem is that your trying to access the Metasprite* variables (by .importzp) and the objects as a 1 byte address at the same time. When you set the DP register all 1 byte addresses will be added to DP to form the effective address.What do you mean by "When you set the DP register all 1 byte addresses will be added to DP to form the effective address."? What are the "1 byte addresses?"
- Drew Sebastino
- Formerly Espozo
- Posts: 3496
- Joined: Mon Sep 15, 2014 4:35 pm
- Location: Richmond, Virginia
Re: SNES Programing Help 2
So what's wrong then? Isn't what I've done correct? XPosition is 2, and I am adding 2 to the table offset + the object's offset.