8x16 and whatever else unreg wants to know

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

unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 sprite is really a 16x32 pixel image?

Post by unregistered »

tokumaru wrote:Bregalad's formula is correct, for when there are 7 items per row.
... ...Yeay! :idea: :o Thanks tokumaru! :D
tokumaru wrote: The formula for reading data from a 2D array which is stored in memory linearly is always Y * ElementsPerRow + X, that doesn't change. But you also have to take into consideration that the base unit is the type of element you are accessing, in this case, metatiles. If you have pixel coordinates, you have to first convert them to metatile coordinates, hence the need to divide both X and Y by the dimensions of your metatiles before applying that formula.

Another thing that will affect how you apply the formula is how your levels are stored in RAM/ROM. If you store it screen by screen, then ElementsPerRow will always be the same, because the number of metatiles per screen doesn't change. If you don't divide your level in screens, then ElementsPerRow will be the length of the entire level, and it will vary from level to level. IMO, things are easier if you divide the levels into screens, because the metatile offsets will always fit in 8 bits, and the multiplications/divisions can be easily done with shifts.
And cause it would be easy for my sister to edit the screens. The blue part below is almost how she did it! :) I never thought of not dividing the level into separate screens... that would be kind of insane :P I think. But it does sound like it would be easy scrolling beyond 2 screens; though I don't know how to... ...yet. :)


tokumaru wrote:Here comes another (untested) example of data arrangement (and how to access it):

codeLevelMap:

;first screen:
.db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
;(another 12 rows here)
.db $10, $10, $10, $10, $10, $10, $10, $10, $10, $10, $10, $10, $10, $10, $10, $10

;second screen:
.db $00, $00, $00, $00, $00, $10, $10, $00, $00, $00, $00, $00, $00, $00, $00, $00
.db $00, $00, $00, $00, $00, $10, $10, $00, $00, $00, $00, $00, $00, $00, $00, $00
;(another 12 rows here)
.db $10, $10, $20, $20, $20, $20, $20, $20, $20, $21, $22, $23, $00, $00, $00, $00

;third screen:
.db $22, $00, $22, $00, $22, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.db $22, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
;(another 12 rows here)
.db $20, $20, $20, $20, $10, $10, $10, $10, $10, $10, $10, $10, $10, $10, $10, $10

;(keep going for as many screens as you want)


;Reads the index of the metatile at position (PointX, PointY) in the level map
ReadMetatile:

;get the index of the screen
ldy PointX+1

;multiply it by 240 (using a look-up table) and add it to the base
;address of the level to create a pointer to the screen we need
clc
lda ScreenOffsetLo, y
adc LevelMap+0
sta ScreenPointer+0
lda ScreenOffsetHi, y
adc LevelMap+1
sta ScreenPointer+1

;calculate the index of the metatile: (Y / 16) * 16 + (X / 16)
lda PointX+0
lsr
lsr
lsr
lsr
sta Temp
lda PointY+0
and #%11110000
ora Temp
tay

;read the metatile
lda (ScreenPointer), y

;return
rts
/code
Now you can do whatever you want with that information. Want to know if that metatile is solid? Do something like this:

Code: Select all

	tax
	lda MetatileCollision, x
	and #BITTHATINDICATESWHETHERAMETATILEISSOLID
	beq +NotSolid
Swell... incredible! That takes less cycles. But it takes a bit more space no... memory. Fast is class! :D
tokumaru wrote: Want to know what is the top left tile of that metatile?

Code: Select all

	tax
	lda MetatileTopLeft, x
Aw yes faster code! :)

Ok I slowly changed my code to be just like your code all today. Time to sleep.
But, I haven't implemented any of this bit of your yellow code up there... I just tried to use my variables. :oops: I got the first part of my code to look like the first part of your code. Now the lady sprite falls just halfway down the screen and then pauses. She is susposed to fall to the bottom of the screen. :( My code at the end is still the same:

Code: Select all

0C3DB                              
0C3DB                              ;GRAVITY
0C3DB C6 31                        dec tC
0C3DD 10 02                        bpl +skip
0C3DF                              
0C3DF B1 0C                        lda (rhombusCollision_low), y
0C3E1                           
0C3E1                                 ;if the metatile is not solid
0C3E1 0A                             asl a    ;<pushes bit #7 into carry.
0C3E2 90 09                          bcc +skip
0C3E4                           
0C3E4                                   ;then fall to the metatile below...
0C3E4                           
0C3E4 B1 1A                            ;lda (UCollision_low), y
0C3E6 A5 05                            lda oY
0C3E8 18                               clc 
0C3E9 69 08                            adc #8
0C3EB 85 05                            sta oY
0C3ED                           +skip  
0C3ED                              
0C3ED E6 31                        ;inc tC
0C3EF                              
0C3EF 60                        rts ;end of unpack and end of daprg-collisionU
That line ;lda (UCollision_low), y is commented because it doesn't really work... should load accumulator with 0 for air or 1 for solid. But, I'm not working any more right now... haven't solved it yet... maybe you could? It's perfectly ok if yall don't. To sleep I go... goodnight. Ohhhh and thanks tokumaru, for all of the great help!! :D I'm almost done... will post some more tomorrow afternoon.

edit: Ok... I want to say that I know that the yellow text will help me to make my game... almost... to make our game more like a machiene. A machiene with parts that work flawlessly together... I remember that tokumaru. :)
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: 8x16 sprite is really a 16x32 pixel image?

Post by tokumaru »

unregistered wrote:I haven't implemented any of this bit of your yellow code
That code is just a multiplication by 240, which is faster with a table, but this table needs 512 bytes, which you might not want to dedicate to this purpose. Another way to multiply X by 240 is to do (X * 256) - (X * 16). Here's a replacement for that calculation, without using tables:

Code: Select all

	;put (screen index * 16) into ScreenPointer
	lda PointX+1
	lsr
	lsr
	lsr
	lsr
	sta ScreenPointer+1
	lda PointX+1
	asl
	asl
	asl
	asl
	sta ScreenPointer+0

	;subtract it from (screen index * 256)
	sec
	lda #$00
	sbc ScreenPointer+0
	sta ScreenPointer+0
	lda PointX+1
	sbc ScreenPointer+1
	sta ScreenPointer+1

	;add the result to the base address of the level
	clc
	lda ScreenPointer+0
	adc #<LevelMap
	sta ScreenPointer+0
	lda ScreenPointer+1
	adc #>LevelMap
	sta ScreenPointer+1
It's much slower though. BTW, in my old code I used LevelMap+0 and LevelMap+1 by mistake, I should have used #<LevelMap and #>LevelMap instead.
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 sprite is really a 16x32 pixel image?

Post by unregistered »

My sprite has started out in the lower left corner all day today... I can't figure out why. :oops:
Is there something wrong in the code I've been trying to set?

Code: Select all

0C3B3                           ;**********************************************************************************************
0C3B3                           unpack:
0C3B3                           
0C3B3                           ;**********************************************************************************************
0C3B3                           
0C3B3                           ;128  64  32  16   8   4   2   1   
0C3B3                           ;$80 $40 $20 $10 $08 $04 $02 $01
0C3B3 A9 3C                         lda #<MetatileRhombus
0C3B5 85 0C                     	sta rhombusCollision_low
0C3B7 A9 C8                     	lda #>MetatileRhombus
0C3B9 85 0D                     	sta rhombusCollision_high
0C3BB                           	
0C3BB A9 1B                     	lda #<MetatileCollision
0C3BD 85 1A                     	sta UCollision_low
0C3BF A9 C9                     	lda #>MetatileCollision
0C3C1 85 1B                     	sta UCollision_high
0C3C3                           	
0C3C3                           	
0C3C3                           ;	clc
0C3C3                           ;	lda ScreenOffsetLo, y
0C3C3                           ;	adc #<LevelMap
0C3C3                           ;	sta ScreenPointer+0
0C3C3                           ;	lda ScreenOffsetHi, y
0C3C3                           ;	adc #>LevelMap
0C3C3                           ;	sta ScreenPointer+1
0C3C3                           	
0C3C3                           
0C3C3 A5 04                     	lda oX
0C3C5 85 28                     	sta PointX
0C3C7 A5 1C                     	lda oY+23
0C3C9 85 2A                     	sta PointY
0C3CB                           	
0C3CB 20 F5 C3                  	jsr linear_position ;y holds new linear position
0C3CE                           		
0C3CE                           	
0C3CE                           	;GRAVITY
0C3CE                           		
0C3CE 85 FF                     	sta $ff
0C3D0 B1 10                     	lda (ten_low), y
0C3D2 A8                        	tay
0C3D3 B1 0C                     	lda (rhombusCollision_low), y
0C3D5                           
0C3D5                                 ;if the metatile is not all the same tile
0C3D5 0A                        	  asl a    ;<pushes bit #7 into carry.
0C3D6 90 1C                     	  bcc +skip
0C3D8                           
0C3D8                                 ; and if the ground below is not something solid to stand on...
0C3D8 A5 2C                     	  lda SomethingSolidtoStandon
0C3DA F0 18                     	  beq +skip
0C3DC                                   ;then fall to the metatile below...
0C3DC                           		
0C3DC A5 05                     	 -- lda oY
0C3DE 18                        	    clc 
0C3DF 69 08                     	    adc #8
0C3E1 85 05                     	    sta oY
0C3E3                           		
0C3E3 85 2A                             sta PointY
0C3E5 20 F5 C3                  		jsr linear_position
0C3E8                           		
0C3E8                           		;and check the value of the block
0C3E8                           ;		tay
0C3E8 B1 10                     		lda (ten_low), y 
0C3EA A8                        	    tay
0C3EB B1 1A                     		lda (UCollision_low), y
0C3ED 85 2C                     		  sta SomethingSolidtoStandon
0C3EF                           		  ;if it is 00 it's air
0C3EF D0 03                     		  bne +notair
0C3F1                           		    ;it is air!!!
0C3F1 4C DC C3                  			jmp --
0C3F4                           		  +notair
0C3F4                           		  ;and if it is 01 it's solid. :)  So try to stop or move back to the previous tile?
0C3F4                                     
0C3F4                           		    ;it's probably solid!!!
0C3F4                           			  ;so stop falling
0C3F4                           			
0C3F4                           
0C3F4                           
0C3F4                           +skip
0C3F4                           	
0C3F4                           		
0C3F4 60                        rts ;end of unpack 
0C3F5                           
0C3F5                           linear_position:
0C3F5                           	; Calculate the index of the metatile: (Y / 16) * 16 + (X / 16) = LINEAR_POSITION  p.50
0C3F5 A5 28                     	lda PointX+0
0C3F7 4A                        	lsr a ;divide my X coordinate by (2 * 2 * 2 * 2) = 16
0C3F8 4A                        	lsr a ;<----------------------------*
0C3F9 4A                        	lsr a ;<--------------------------------*
0C3FA 4A                        	lsr a ;<------------------------------------*
0C3FB AA                        	  tax
0C3FC 85 37                     	sta tC+1
0C3FE A5 2A                     	lda PointY+0
0C400 29 F0                     	and #11110000b
0C402 05 37                     	ora tC+1
0C404 A8                        	tay
0C405                           
0C405 60                            rts
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 sprite is really a 16x32 pixel image?

Post by unregistered »

Yessss! :D

Ok it's fixed now... I found out this morning that the -- loop is too tiny! When you delete that loop part and let it end with storing the new value of SomethingSolidtoStandon... then it works!! :D She falls ............................................. down into the ground and sticks there. I would like to see her fall and stop with her feet on the ground. Is this a good method?: Calculate the block above her hand... she has her hands high in the air. Do I just subtract 16 inside each calculation? Or maybe I should add 16 to her height so that checks the block near her feet? :? I'm kind confused about what to do. I'll figure it out sometime. :oops:
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: 8x16 sprite is really a 16x32 pixel image?

Post by tokumaru »

The exact points that make contact with surfaces can be anything you want. I have no idea how you're handling object coordinates, but I assume you have the current coordinates of the girl characters stored somewhere, which you use to calculate the coordinates of the individual sprites. Similarly to how you calculate sprite coordinates from these "master coordinates", you can also calculate the collision points.

If the character is 16x32 pixels, and its coordinates indicate its top left corner, you can calculate a point of collision at the middle bottom of the character with X+8, Y+32. Once you know this point (PointX, PointY), you can call that routine that checks the metatile at that location. If it's not solid, the character should fall. If it is solid, you can't simply stop it from falling (because the character could be stuck into the ground if moving faster than 1 pixel per frame), you have to push it back up so that it's exactly on top of the floor.
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 sprite is really a 16x32 pixel image?

Post by unregistered »

Grand!!! Thlink I have it!!

edit: Well... now she starts way up high and falls a little bit...then stops... well above the ground. It's kind of exciting!!!!!!!!!!!!!! ALMOST THERE... SHE JUST NEEDS TO FALL FOR A LITTLE BIT LONGER!! :D

edit2: Now she falls to the ground and sticks inside it a little!
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 sprite is really a 16x32 pixel image?

Post by unregistered »

tokumaru wrote:The exact points that make contact with surfaces can be anything you want. I have no idea how you're handling object coordinates, but I assume you have the current coordinates of the girl characters stored somewhere, which you use to calculate the coordinates of the individual sprites. Similarly to how you calculate sprite coordinates from these "master coordinates", you can also calculate the collision points.

If the character is 16x32 pixels, and its coordinates indicate its top left corner, you can calculate a point of collision at the middle bottom of the character with X+8, Y+32. Once you know this point (PointX, PointY), you can call that routine that checks the metatile at that location. If it's not solid, the character should fall. If it is solid, you can't simply stop it from falling (because the character could be stuck into the ground if moving faster than 1 pixel per frame), you have to push it back up so that it's exactly on top of the floor.
HOW?? I get that it is time to add eight... but where ever I put the

Code: Select all

          sec
          lda oY
          sbc #8
          sta oY
it makes our girl character not move at all... every time my function subtracts 8 right after it added 8... and so she doesn't fall... ever! :( How would you make this work correctly? My logic has it check the block below and add eight if it's air and then quit after reading the type of block below. That happens every time. :?
User avatar
Kasumi
Posts: 1293
Joined: Wed Apr 02, 2008 2:09 pm

Re: 8x16 sprite is really a 16x32 pixel image?

Post by Kasumi »

You can't subtract by a fixed amount. If she's one pixel in the floor and you subtract eight, she's flying. If she's 9 pixels in the floor and you subtract 8 she's still in the floor.

You have to figure out how far she needs to be ejected, and then eject her.

If you've got 16x16 metatiles, only the lowest four bits of her lowest coordinate byte matter. You check if she's in a collision enabled tile.

Now think. If the lowest bits of her position are $0, how many pixels does she need to move up? How about when she's at $F? Once you figure that out, figure out some math to make it always eject her immediately out the tile.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: 8x16 sprite is really a 16x32 pixel image?

Post by tokumaru »

unregistered wrote:it makes our girl character not move at all... every time my function subtracts 8 right after it added 8... and so she doesn't fall... ever!
Pushing her back up is something you should do only if her feet are into the floor, not all the time. And like Kasumi said, you can't just push her a fixed amount of pixels.

The math should be quite simple really, since your solid metatiles are always 16x16 pixels... Say that you checked point X + 8, Y + 32 of a 16x32 character, and you found the metatile at that position to be solid. This means you have to make the character "snap" to the metatile that's above this one. You can ignore how far into the floor the character is with PointY AND #%f0, which is the pixel coordinate of the very top (first row) of the solid metatile. Then, it's just a matter of subtracting the character's height to find the new Y coordinate that will place it right above the floor.
My logic has it check the block below and add eight if it's air and then quit after reading the type of block below. That happens every time. :?
And if the block below is solid, you must push the character back up. You can do it that way, but you'll have no acceleration at all (because you always add 8), and that looks very bad. The speed of falling objects increases with time, so it would be better that you added a variable instead of a constant number, and every frame that the character is in the air the value of that variable increases. However, if you increase the speed by whole pixels every frame it will grow too fast and you'll barely notice it, so you should probably look into fixed point math, so that you can add fractional numbers to the character's speed to make it more smooth.
Last edited by tokumaru on Mon Oct 15, 2012 10:17 pm, edited 1 time in total.
User avatar
thefox
Posts: 3134
Joined: Mon Jan 03, 2005 10:36 am
Location: 🇫🇮
Contact:

Re: 8x16 sprite is really a 16x32 pixel image?

Post by thefox »

tokumaru wrote:(because you always add 8)
Can we get rid of that smiley on the forum? Way more often I see it used accidentally rather than intentionally. Or maybe the accidental uses just stick out...
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: 8x16 sprite is really a 16x32 pixel image?

Post by tokumaru »

Yeah, I always get screwed by that stupid smiley...
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 sprite is really a 16x32 pixel image?

Post by unregistered »

tokumaru wrote:
unregistered wrote:My logic has it check the block below and add eight if it's air and then quit after reading the type of block below. That happens every time. :?
And if the block below is solid, you must push the character back up. You can do it that way, but you'll have no acceleration at all (because you always add 8), and that looks very bad. The speed of falling objects increases with time, so it would be better that you added a variable instead of a constant number, and every frame that the character is in the air the value of that variable increases. However, if you increase the speed by whole pixels every frame it will grow too fast and you'll barely notice it, so you should probably look into fixed point math, so that you can add fractional numbers to the character's speed to make it more smooth.
Fixed point math. OK... I found this pdf and have read it and understand most of it... i think. I have kind of choose to use Q3.5 nums... on page 13 of that pdf i think I remember. Would something like that work well for this falling faster math? Or they show a Q3.13 also. That's a 2 byte value.

...While reading the pdf it reminded me of Calculus... I was able to retake my calculus class... so I learned it twice... I guess. Those 2 semesters were quite a time ago though... I think. :)

edit: tokumaru,
tokumaru[color=#80FF00], on page 50,[/color] wrote:EDIT: Damn 8) smiley!
how did you do that? :o
User avatar
Kasumi
Posts: 1293
Joined: Wed Apr 02, 2008 2:09 pm

Re: 8x16 sprite is really a 16x32 pixel image?

Post by Kasumi »

In this case it's really more of change in perception than learning anything new.

You have two bytes. Together, they represent one number.
You're probably familiar with this way.
Number = hibyte*256+lobyte for a range of 0 through 65535.

But the computer really doesn't care about what the bytes represent to you.

Number could also represent onebyte + (otherbyte/256) to you for a range of 0 through 255+(255/256). In this case "otherbyte" represents the fractional part of a number.

In both cases additions/subtractions to the bytes are done in exactly the same way, they just represent something different for you, the programmer.

A speed like this:
onebyte = #$01
otherbyte = #$00
added to the characters position means the character moves one pixel every frame.
A speed like this:
onebyte = #$00
otherbyte = #$40
added means the character moves one pixel every 4 frames. (Because that's how many adds of that amount it would take to carry 1 pixel over)

(This also means your position will need another byte to represent the fractional part of the position, which if you scroll means you'll need at least 3 bytes for the position alone, two for the speed)

At least, that's one way to set it up. Make sense?
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: 8x16 sprite is really a 16x32 pixel image?

Post by tepples »

The code 8) used to make the emoticon with sunglasses. As of two minutes ago, I have turned it off in favor of 8-), which produces 8-).
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: 8x16 sprite is really a 16x32 pixel image?

Post by tokumaru »

unregistered wrote:I have kind of choose to use Q3.5 nums... on page 13 of that pdf i think I remember. Would something like that work well for this falling faster math? Or they show a Q3.13 also.
Those will make it hard to use the integer part of the values... Kasumi's suggestion of using 1 byte for the integer part and another for the fractional part (i.e. 8.8) makes much more sense. That way you easily use the high byte as the integer part as is, without having to shift bits around.
how did you do that? :o
How did I do what? Show 8 and ) instead of the smiley? There's a checkbox in below the text area in the posting/editing page that disables smileys in the current post.
Post Reply