Creating a data structure.

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

puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Creating a data structure.

Post by puppydrum64 »

I'm doing something a little bit simpler at the moment. It's an NROM game called Aquarium Simulator. It's also a way to test out a data structure concept that works like this:

A single page of NES Work RAM is dedicated to this data structure. It allows a maximum of 16 "objects" to exist on screen at once. These include the player cursor (which is always object zero), as well as the fish in the aquarium, fish food, air bubbles, etc. If an object is "created," the game will check to see if there are any empty object slots, and if not, no object is created. Otherwise the object's data will be stored in the lowest empty slot. If an object is "destroyed" the slot that object was in will be emptied.



This system is similar to the one NESMaker uses (and I have some hesitation using it since I'm concerned it's a little too similar, despite owning a license for the software I'm not using it to make this game, but I digress).

I'm trying to test out this system by "creating" three objects, with just enough data needed for the structure to function. Their object ID, X position, and Y position are all loaded, and the OBJECT_SLOTS variable in that column are set to 1 indicating an active object is contained within. Then I created this loop which was intended to copy the info needed to actually draw those objects on screen into shadow OAM. However, it failed producing a big mess of sprites all over the place. I'm not sure what went wrong, and it's difficult to debug this since I can't actually see any sprites appear in the PPU Viewer until after DMA occurs (and by then it's too late to see what is actually happening in the loop that's causing the failure.)

Here's the code. Again, please forgive the wonky formatting; that's something that keeps happening when I copypaste from Notepad++ to these forums.

Hopefully you all could be so kind as to help me with the following questions:
1. Is this a good or bad way to go about creating a data structure?
2. What went wrong with my loop?
3. Did I explain this data structure well enough?
4. Is this too similar to NESMaker's code for me to publish this game independently?

Code: Select all

	TOTAL_MAX_OBJECTS = 16
	
	.enum $0500		;OBJECT RAM
	
	OBJECT_XPOS		.dsb TOTAL_MAX_OBJECTS
	OBJECT_YPOS		.dsb TOTAL_MAX_OBJECTS

	OBJECT_ID			.dsb TOTAL_MAX_OBJECTS			;$0430
		
								
	OBJECT_SIZE					.dsb TOTAL_MAX_OBJECTS 		   ;$0450	Total number of sprites needed to display the object.
	
	OBJECT_SLOTS				.dsb TOTAL_MAX_OBJECTS 		   ;$0490	0 if empty, otherwise that slot is occupied.

	
	.ende
INIT:


	
	;WE WILL TEST THIS INIT CODE BY STARTING WITH THREE OBJECTS: THE CURSOR, A BUBBLE, AND A BETTA FISH.
	
	LDX #$00
	LDA #$01
	STA OBJECT_SLOTS,x
	STA OBJECT_SLOTS+1,x
	STA OBJECT_SLOTS+2,x
	
	LDA #$00
	STA OBJECT_ID,x
	LDA #$01
	STA OBJECT_ID+1,x
	LDA #$02
	STA OBJECT_ID+2,x
	
	LDA #$80
	STA OBJECT_XPOS,x
	STA OBJECT_YPOS,x
	
	LDA #$40
	STA OBJECT_XPOS+1,x
	STA OBJECT_YPOS+1,x
	
	LDA #$20
	STA OBJECT_XPOS+2,x
	STA OBJECT_YPOS+2,x
	
	;x should still be zero.
	
	;LDX #$00
outer_loop_init:			;X = the object slot being copied to OAM. Y = which sprite's data is being copied.

	LDA OBJECT_SLOTS,x
	BNE continueToDrawObject	;if the slot is empty don't draw anything in it.
	JMP skip
continueToDrawObject:
	LDA OBJECT_ID,x
	TAY						;use as index into object_id lut.
	
	LDA OBJECT_ID_LO,y
	STA pointerLo
	LDA OBJECT_ID_HI,y
	STA pointerHi
	
	LDY #$00
	STY looptempY			;we can't use pointers without Y, and Y needs to be zero for this to work. So we'll have to do something messy. 
	
inner_loop_init:
	LDA (pointerLo),y	;y pos
	CLC
	ADC OBJECT_YPOS,x
	STA temp0			;store y congruent to 0 mod 4 into temp0
	INY
	
	LDA (pointerLo),y	;tile
	STA temp1			;store y congruent to 1 mod 4 into temp1
	INY
	
	LDA (pointerLo),y	;attribute data
	STA temp2			;store y congruent to 2 mod 4 into temp2
	INY
	
	LDA (pointerLo),y	;x pos
	CLC
	ADC OBJECT_XPOS,x
	STA temp3			;store y congruent to 3 mod 4 into temp3
	INY					;now Y is congruent to 0 mod 4 again.
	
	;now we need y to equal the number of times we've done the above.
	TYA
	PHA
	
	LDY looptempY
	LDA temp0
	STA $0200,y
	LDA temp1
	STA $0201,y
	LDA temp2
	STA $0202,y
	LDA temp3
	STA $0203,y
	INC looptempY
	PLA
	TAY
	;now we need to see if we've drawn all the sprites we need to draw.
	LDA looptempY
	CMP OBJECT_SIZE,x	;x did not change throughout the entire inner loop.
	BNE inner_loop_init
	
	;we've finished drawing all the sprites for this game object, so increment x so that we can draw the next one.
skip:
	INX
	CPX TOTAL_MAX_OBJECTS-1
	BNE outer_loop_init
And here are the relevant lookup tables:

Code: Select all

OBJECT_ID_LO:		;tells us WHERE to collect OAM data from.
	.byte #<cursor, #<bubble, #<fish_betta

OBJECT_ID_HI:		;tells us WHERE to collect OAM data from.
	.byte #>cursor, #<bubble, #<fish_betta

DEFAULT_OBJECT_SIZE:		;tells us how many times to loop during OAM setup.
	.byte #$04,#$01,#$08
	
fish_betta:	;format: y,tile,attrib,x
				.byte 0,$23,2,0
				.byte 0,$22,2,-8
				.byte 0,$21,2,-16
				.byte 0,$20,2,-24
				.byte -8,$13,2,0
				.byte -8,$12,2,-8
				.byte -16,$11,2,-16
				.byte -24,$10,2,-24
				
cursor:
				.byte 0,$08,0,0
				.byte 0,$09,0,8
				.byte 8,$18,0,0
				.byte 8,$19,0,8
				
				
bubble:			
				.byte 0,$01,0,0
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: Creating a data structure.

Post by unregistered »

Sprite debugging becomes so much easier, while using Mesen and having its Memory Tools open, if, in the View: box, you select “Sprite / OAM RAM”.

That way you aren’t waiting for the screen’s sprites to change; rather, you get to instantly see the PPU’s OAM sprite values that will cause the sprites to appear in the near furure. 🙂


And if your Memory Tools is set to highlight new bytes written to, it makes the process sooo much nicer.
User avatar
Controllerhead
Posts: 314
Joined: Tue Nov 13, 2018 4:58 am
Location: $4016
Contact:

Re: Creating a data structure.

Post by Controllerhead »

puppydrum64 wrote: Thu May 27, 2021 3:46 pm

Code: Select all

	CPX TOTAL_MAX_OBJECTS-1
I don't know if there are other issues, but try CPX #TOTAL_MAX_OBJECTS-1

I believe you're currently referring to whatever is in $0E.
Image
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: Creating a data structure.

Post by puppydrum64 »

Well it draws the first object correctly but then starts looping out of bounds. I'm too tired to look at it any more tonight but I'll leave this here for now, just in case someone can figure it out.
Aquarium_Simulator.nes
(24.02 KiB) Downloaded 65 times
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: Creating a data structure.

Post by puppydrum64 »

Controllerhead wrote: Thu May 27, 2021 4:53 pm
puppydrum64 wrote: Thu May 27, 2021 3:46 pm

Code: Select all

	CPX TOTAL_MAX_OBJECTS-1
I don't know if there are other issues, but try CPX #TOTAL_MAX_OBJECTS-1

I believe you're currently referring to whatever is in $0E.
Yeah, that was part of the problem. I had a few typos in the lookup tables too. But it's still broken for some other reason. Does what I'm trying to do make sense? I feel like there's a better way to write the loop that's not so convoluted.

EDIT: Just fixed it (for now) but I think there's still a bug where it loops through the inner loop on empty object slots even though it really shouldn't.
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: Creating a data structure.

Post by unregistered »

puppydrum64 wrote: Thu May 27, 2021 3:46 pm

Code: Select all

	TOTAL_MAX_OBJECTS = 16
	
	.enum $0500		;OBJECT RAM
	
	OBJECT_XPOS		.dsb TOTAL_MAX_OBJECTS
	OBJECT_YPOS		.dsb TOTAL_MAX_OBJECTS

	OBJECT_ID			.dsb TOTAL_MAX_OBJECTS			;$0430
		
								
	OBJECT_SIZE					.dsb TOTAL_MAX_OBJECTS 		   ;$0450	Total number of sprites needed to display the object.
	
	OBJECT_SLOTS				.dsb TOTAL_MAX_OBJECTS 		   ;$0490	0 if empty, otherwise that slot is occupied.

	
	.ende
INIT:


	
	;WE WILL TEST THIS INIT CODE BY STARTING WITH THREE OBJECTS: THE CURSOR, A BUBBLE, AND A BETTA FISH.
	
	LDX #$00
	LDA #$01
	STA OBJECT_SLOTS,x
	STA OBJECT_SLOTS+1,x
	STA OBJECT_SLOTS+2,x
	
	LDA #$00
	STA OBJECT_ID,x
	LDA #$01
	STA OBJECT_ID+1,x
	LDA #$02
	STA OBJECT_ID+2,x
	
	LDA #$80
	STA OBJECT_XPOS,x
	STA OBJECT_YPOS,x
	
	LDA #$40
	STA OBJECT_XPOS+1,x
	STA OBJECT_YPOS+1,x
	
	LDA #$20
	STA OBJECT_XPOS+2,x
	STA OBJECT_YPOS+2,x
	
	;x should still be zero.
	
	;LDX #$00
outer_loop_init:			;X = the object slot being copied to OAM. Y = which sprite's data is being copied.

	LDA OBJECT_SLOTS,x
	BNE continueToDrawObject	;if the slot is empty don't draw anything in it.
	JMP skip
continueToDrawObject:
	LDA OBJECT_ID,x
	TAY						;use as index into object_id lut.
	
	LDA OBJECT_ID_LO,y
	STA pointerLo
	LDA OBJECT_ID_HI,y
	STA pointerHi
	
	LDY #$00
	STY looptempY			;we can't use pointers without Y, and Y needs to be zero for this to work. So we'll have to do something messy. 
	
inner_loop_init:
	LDA (pointerLo),y	;y pos
	CLC
	ADC OBJECT_YPOS,x
	STA temp0			;store y congruent to 0 mod 4 into temp0
	INY
	
	LDA (pointerLo),y	;tile
	STA temp1			;store y congruent to 1 mod 4 into temp1
	INY
	
	LDA (pointerLo),y	;attribute data
	STA temp2			;store y congruent to 2 mod 4 into temp2
	INY
	
	LDA (pointerLo),y	;x pos
	CLC
	ADC OBJECT_XPOS,x
	STA temp3			;store y congruent to 3 mod 4 into temp3
	INY					;now Y is congruent to 0 mod 4 again.
	
	;now we need y to equal the number of times we've done the above.
	TYA
	PHA
	
	LDY looptempY
	LDA temp0
	STA $0200,y
	LDA temp1
	STA $0201,y
	LDA temp2
	STA $0202,y
	LDA temp3
	STA $0203,y
	INC looptempY
	PLA
	TAY
	;now we need to see if we've drawn all the sprites we need to draw.
	LDA looptempY
	CMP OBJECT_SIZE,x	;x did not change throughout the entire inner loop.
	BNE inner_loop_init
	
	;we've finished drawing all the sprites for this game object, so increment x so that we can draw the next one.
skip:
	INX
	CPX TOTAL_MAX_OBJECTS-1
	BNE outer_loop_init
Hmmm…

Code: Select all

;why are you using sta abs,x in your init
;when you aren’t even using x there? :)
;Each sta abs is quicker and smaller in size (less bytes).

;The loop might be simpler:

INIT:
;init code here

ldx #TOTAL_MAX_OBJECTS
outer_loop_init:
dex
beq end_me ;or, the exit label
lda OBJECT_SLOTS, x
beq outer_loop_init

continue_to_draw_object:
. . .
inner_loop_init:
. . .
jmp outer_loop_init
1.) See, with dex you get to skip the cpx each loop bc the zero flag will automatically be set when x becomes zero.

And, this is just an example… so I’m not sure the dex of the outer_loop will play nicely with the inner_loop.

2.) For your inner_loop why use Temp0 through Temp4? That way you have to store and load the Temp value before shadow OAM becomes written to; why not just store to $0200,y each time and just increment y after every sprite-byte write? Then you would no longer need looptempY. :)

tokumaru had me create zeropage variable oamIndex so I could just load that each time. oamIndex
tomumaru wrote:is a variable tracking how far you’ve written into shadow OAM (customarily at $0200-$02FF)

Ahh, and so that oamIndex requires inx. So I used a dec with a temp variable… to allow the compare-free decrement. (My code is a bit weird, but it works. :) )
Oziphantom
Posts: 1565
Joined: Tue Feb 07, 2017 2:03 am

Re: Creating a data structure.

Post by Oziphantom »

Code: Select all

	LDY looptempY
	LDA temp0
	STA $0200,y
	LDA temp1
	STA $0201,y
	LDA temp2
	STA $0202,y
	LDA temp3
	STA $0203,y
	INC looptempY
	PLA
	TAY
you only increase the loopTempY by 1, but you need to move + 4 to get to the next sprite.

Code: Select all

	PLA
	TAY
	;now we need to see if we've drawn all the sprites we need to draw.
	LDA looptempY
	CMP OBJECT_SIZE,x	;x did not change throughout the entire inner loop.
	BNE inner_loop_init
	
I think here you mean to compare against the restored value in A, not the Y we wrote to the OAM mirror with. so just

Code: Select all

pla
tay
cmp Object_SIZE,x
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: Creating a data structure.

Post by puppydrum64 »

Later that night that I originally posted this, I figured out what I was doing wrong and I rewrote the loop with improved clarity. It's probably not optimal (Even though looping backwards is faster, I prefer to use inx/iny since it's easier to understand and I really don't notice much difference. This game is called Aquarium Simulator after all so there's no real urgency and therefore not a huge demand for highly optimized code... yet.)

Code: Select all

generateOAM:
	LDY #$00
	STY looptempX			;looptempX tells us if we are done drawing the object.
	STY looptempY			;looptempY ensures we copy the object data to the correct slot of OAM.
outer_loop_init:			;X = the object slot being copied to OAM. Y = which sprite's data is being copied.

	LDA OBJECT_SLOTS,x
	BNE continueToDrawObject	;if the slot is empty don't draw anything in it.
	JMP skip
continueToDrawObject:
	LDA OBJECT_ID,x
	TAY						;use as index into object_id lut.
	
	LDA OBJECT_ID_LO,y
	STA pointerLo
	LDA OBJECT_ID_HI,y
	STA pointerHi
	
	LDY #$00 			;we can't use pointers without Y, and Y needs to be zero for this to work. So we'll have to do something messy. 
	STY looptempX		;reset looptempX, which tells us when we're done drawing the sprite. The variable name is a bit misleading I know.
inner_loop_init:
	LDA (pointerLo),y		;y pos
	CLC
	ADC OBJECT_YPOS,x
	STA temp0			;store y congruent to 0 mod 4 into temp0
	INY
	
	LDA (pointerLo),y		;tile
	STA temp1			;store y congruent to 1 mod 4 into temp1
	INY
	
	LDA (pointerLo),y		;attribute data
	STA temp2			;store y congruent to 2 mod 4 into temp2
	INY
	
	LDA (pointerLo),y		;x pos
	CLC
	ADC OBJECT_XPOS,x
	STA temp3			;store y congruent to 3 mod 4 into temp3
	INY					;now Y is congruent to 0 mod 4 again.
	
	;now we need y to equal the number of times we've done the above.
	TYA
	PHA
	
	LDA looptempY
	ASL A
	ASL A
	TAY
	
	LDA temp0
	STA $0200,y
	LDA temp1
	STA $0201,y
	LDA temp2
	STA $0202,y
	LDA temp3
	STA $0203,y
	INC looptempX
	INC looptempY
	
	PLA
	TAY
	
	;now we need to see if we've drawn all the sprites we need to draw.
	LDA looptempX
	CMP DEFAULT_OBJECT_SIZE,x	;x did not change throughout the entire inner loop.
	BNE inner_loop_init
	;end of inner loop
	;we've finished drawing all the sprites for this game object, so increment x so that we can draw the next one.
skip:
	INX
	CPX #TOTAL_MAX_OBJECTS-1
	BNE outer_loop_init
	;end of outer loop
	
	RTS
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: Creating a data structure.

Post by puppydrum64 »

While I'm here though I'd like to ask another question. I'm trying to create an RNG-based movement function for the fish in the tank. It's very simple and isn't really all that random but it's good enough I believe. The only problem is that the fish tends to get stuck at the top of the tank. I'm not sure if it's a bias in my random number generator or due to how I programmed the bounding boxes for my game world. And I'm really not sure how to figure that out. I'll link both below as well as the game itself.

Here's the random movement code.

Code: Select all

MoveRandomly:		;INPUT: X= the object slot of the object that is using this behavior this frame.
	TXA
	PHA
	LDA randomTimer
	AND #%00011111			;slow the fish down a bit.
	BNE @nomoving
		LDA randomSeed
		AND #%00000111		;get what it's congruent to mod 8 for direction lookup.
		ASL					;we are indexing into what is essentially a table of words
		TAY					;use Y as index.
;---------------------------		
		LDA OBJECT_XPOS,x	
		CLC
		ADC motion_vectors+1,y
		STA temp0
		CMP #TANK_AREA_LEFT
		BCC @nomoving
		CMP #TANK_AREA_RIGHT
		BEQ @nomoving
		;LDA OBJECT_XPOS,x C motion_vectors+1,y
		STA OBJECT_XPOS,x	;x = the object that is trying to move. 
;---------------------------	
		LDA OBJECT_YPOS,x
		CLC
		ADC motion_vectors,y
		CMP #TANK_AREA_TOP
		BEQ @nomoving
		CMP PLAY_AREA_BOT	;not a typo. This is a memory address unlike the other constants since it is region-dependent.
		BEQ @nomoving
		STA OBJECT_YPOS,x
And here is the RNG routine and the associated values.

Code: Select all

doRNG:	;$C22F
	TXA
	PHA
	
	
	LDA randomTimer
	AND #%00011111		;cap at 31 so we never index out of bounds.
	TAX
	
	LDA log_table,x
	CLC
	ADC joypad1_old		;mix in the player's input to jumble this value even further.
	CLC
	ADC randomSeed		;mix in last call's random seed to jumble this value again!
	STA randomSeed
	
	PLA
	TAX
	RTS
	
log_table:		        ;used for pseudo-random fish behavior. Good enough for what we're doing.
				;Source: National Imagery and Mapping Agency, US Govt, Public Domain

	.byte 00,$32,60,$84,03,$19,31,$38		;We will combine these with player input to produce a random seed.
	.byte $42,43,$39,32,$22,08,$90,70
	.byte 46,$19,88,$55,18,$79,36,$91
	.byte $42,91,$37,80,$21,59,$94,27
	
motion_vectors		;format: y,x  UPLEFT: 0,1  DOWNLEFT: 2,3  ETC. This is essentially a table of words.
	.byte -1,-1,1,-1,-1,1,1,1,-1,0,1,0,0,-1,0,1
I looked at a picture of a logarithm table, took the last 2 digits of each entry, and treated every other one as hexadecimal, except on a new line
to create this sort of checkerboard pattern. It's probably not the best way to go about creating a random number generator but it's the best I could come up with. The randomTimer variable is just a place in zero page that starts at zero and gets incremented every NMI. The final random value is based on the following:
* The value of randomTimer
* The player's button presses last frame
* The logarithm table
* The previous value of this variable.

So long story short, this seems to work to create the appearance of a fish randomly swimming around, but the fish tends to move towards the top of the fish tank and stay there. I wasn't very confident that I programmed the bounding boxes of the area the fish is allowed to travel correctly so I think that may be a cause, but also I've noticed a bit of a bias towards low numbers in my log table. So I'm not sure which is doing it.
Aquarium_Simulator.nes
(24.02 KiB) Downloaded 50 times
User avatar
Controllerhead
Posts: 314
Joined: Tue Nov 13, 2018 4:58 am
Location: $4016
Contact:

Re: Creating a data structure.

Post by Controllerhead »

puppydrum64 wrote: Sat May 29, 2021 11:18 am but also I've noticed a bit of a bias towards low numbers in my log table.
Well you have nothing in the $Ax-$Fx range. The way you have hexadecimal and decimal numbers sprinkled through your table is thumbtacks in my eyes :shock: , but, you shouldn't really need a lookup table anyway (IMO).
puppydrum64 wrote: Sat May 29, 2021 11:18 am The randomTimer variable is just a place in zero page that starts at zero and gets incremented every NMI.
This could be a problem: Your random number will be the same for an entire frame for everything that tries to access it. Personally i use a JSR to generate a new number every time i want one. It looks something like this:

Code: Select all

sub_generateRandom:
  ; Try to generate a random number
  INC randomCount
  LDA random
  ADC randomCount
  ADC p1Hold
  ; ADC perhaps another game related variable
  ADC frameCount
  STA random
end_generateRandom:
  RTS
I use a byte for the random number and another for the access count to make sure it doesn't get stuck on even values.

You can JSR a method like this and it will be in the Accumulator after you RTS and not touch X or Y. Also, i'm sure everyone here has their own opinion about the best way to generate random numbers. I wouldn't take my word as definitive or anything =p
Image
Pokun
Posts: 2681
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Creating a data structure.

Post by Pokun »

One idea is to program a manual mode for the fish where you can control it freely with the d-pad for debugging. Apply the same bounding box logic to this mode so you can easily test that all possible collision situations works.
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: Creating a data structure.

Post by puppydrum64 »

Hang on, I'm having another problem, this time with the assembler itself:

Code: Select all

pressSelect:

	LDA gamePaused
	bne @nomoving			;ASM6 reports an "Unknown Label" error here
	
	;;;UR CODE FOR WHAT HAPPENS WHEN U PRESS SELECT GOES HERE
	INC debugX
	CMP #TOTAL_MAX_OBJECTS
	BCS skipDebugX
	JMP @nomoving		;ASM6 reports an "Unknown Label" error here
skipDebugX:
	LDA #$00
	STA debugX
@nomoving:

	RTS
Weird thing is I use this label quite a bit (since it's local) and have had no issues until now. Please forgive my cringy use of "UR", I used to have it say "YOUR" but then every time I typed the letter "y" Notepad++ would try to autocomplete it as "you" and I didn't want that.
User avatar
Controllerhead
Posts: 314
Joined: Tue Nov 13, 2018 4:58 am
Location: $4016
Contact:

Re: Creating a data structure.

Post by Controllerhead »

I've had trouble with local labels before, so i just don't use them. I know that's not a great answer... :?

Perhaps someone else can explain how the @scope works exactly?

Anyway, you can use generics like + and - for similar situations instead:

Image

PS: You can turn off autocomplete in NP++. I did.
Image
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Creating a data structure.

Post by tokumaru »

skipDebugX is a global label that starts a new local scope, so the code above that can't see the local label @nomoving defined below. That's completely expected and works exactly as documented.

Local labels in ASM6 are pretty shitty though... If possible, use + and - labels instead. For example, +nomoving should work in this case.
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: Creating a data structure.

Post by puppydrum64 »

tokumaru wrote: Sat May 29, 2021 7:54 pm skipDebugX is a global label that starts a new local scope, so the code above that can't see the local label @nomoving defined below. That's completely expected and works exactly as documented.

Local labels in ASM6 are pretty shitty though... If possible, use + and - labels instead. For example, +nomoving should work in this case.
Well I can't really blame anyone but myself for getting that wrong. I just skimmed over that part and interpreted it as "You can reuse label names as long as you put an @ in front and it will work" without a second thought
Post Reply