Collision and Vram

Topics related to the API, programming discussions & questions, coding tips, bugs, etc. should go here.
User avatar
nicksen782
Posts: 714
Joined: Wed Feb 01, 2012 8:23 pm
Location: Detroit, United States
Contact:

Collision and Vram

Post by nicksen782 »

Hi!

I've been reading through these:
http://uzebox.org/wiki/index.php?title=Global_Vram
http://uzebox.org/wiki/index.php?title= ... _Detection

They are informative but I am missing out on how vram works. I understand that it is a VRAM_TILES_H*VRAM_TILES_V sized array. I also understand that in mode 3 that the first tiles in this array are the ram tiles.

What I don't understand is the rest. My goal is to be able to check what tile a sprite occupies. For simplicity my sprite is 1x1. I want to pull the right value out of Vram and then display it near the top of the screen. It seems that all of the screen's tiles are there but they are in the wrong order. Therefore, I believe that I am accessing them wrong.

The kernel settings of my Makefile:

Code: Select all

## Kernel settings
KERNEL_DIR = ../../../kernel
KERNEL_OPTIONS  = -DVIDEO_MODE=3 -DINTRO_LOGO=0 -DSOUND_CHANNEL_4_ENABLE=0 -DSCROLLING=1 -DSOUND_MIXER=1
KERNEL_OPTIONS += -DMAX_SPRITES=5 -DSCREEN_TILES_V=27 -DRAM_TILES_COUNT=1
#
#-DFIRST_RENDER_LINE=24 
KERNEL_OPTIONS += -DVRAM_TILES_V=32
A very messy GetMapTile function (originally taken from Megabomber)

Code: Select all

unsigned char GetMapTile(unsigned char x, unsigned char y, char direction){
//x=x>>3;
//x=x*8;
//y=y>>3;
//y=y+testvalue;
//;index formula is vram[((y>>3)*256)+8x+(y&7)]
	//unsigned char thevalue = (vram[(y*28)+x]-RAM_TILES_COUNT);
	unsigned char thevalue =  	(vram[((y>>3) * VRAM_TILES_H + (x>>3))-RAM_TILES_COUNT]);
	//unsigned char thevalue =  (vram[(y>>3) * VRAM_TILES_H-1 + (x>>3)]);
	//if                     (vram[(y) * VRAM_TILES_H + (x>>3)]) == 18)
	//if                      (vram[(Y>>3) * VRAM_TILES_H + (X>>3)] == TILE_WOOD) 
	Print(22, 3, PSTR("# ")); PrintByte (26, 3, thevalue-RAM_TILES_COUNT, true);
	SetTile(21,3,thevalue-RAM_TILES_COUNT);
	return thevalue-RAM_TILES_COUNT;
	  //return (vram[122+(y*30)+x]-RAM_TILES_COUNT);
}
Am I applying the code wrong? I am not sure how to continue. If I could just get the expected tile to display then I can probably figure out the rest.
CunningFellow
Posts: 1488
Joined: Mon Feb 11, 2013 8:08 am
Location: Brisbane, Australia

Re: Collision and Vram

Post by CunningFellow »

Nicksen,

VRAM is an array that says what tile is at each location.

Think of it as a text mode with 256 colour tiles replacing the ASCII character.

For example if you wanted to put the text "hello, world!" in the top left corner of a text mode you would put

VRAM[0][0] = 'h';
VRAM[0][1] = 'e';
VRAM[0][2] = 'l';
VRAM[0][3] = 'l';
.
.
.
VRAM[0][11] = 'd';
VRAM[0][12] = '!';


In the Uzebox tile modes if you had a 16x16 graphic of a tree that you had broken up into 4x 8x8 pixel tiles and they where tiles 100, 101,102, and 103. If you wanted to put a tree in the top left corner it would be

VRAM[0][0] = 100;
VRAM[0][1] = 101;
VRAM[1][0] = 102;
VRAM[1][1] = 103;

if you wanted to put that same tree at any 8x8 cell X,Y it would be

VRAM[Y][X] = 100;
VRAM[Y][X+1] = 101;
VRAM[Y+1][X] = 102;
VRAM[Y+1][X+1] = 103;

Don't know if this was helpful or not, but thats how I would think of it coming from the world of the 6845
User avatar
nicksen782
Posts: 714
Joined: Wed Feb 01, 2012 8:23 pm
Location: Detroit, United States
Contact:

Re: Collision and Vram

Post by nicksen782 »

Hey CunningFellow,

Yes, I understand that I can change values in vram directly. However, in my case I want to check a value in vram against the tiles that a sprite occupies or will occupy.

I would like to better understand how the vram array is laid out. So far, I've look at existing code and see that it is usually y times how high your screen is and then you add in the x tile that you are at. My sprites are pixel level so I divide by 8 (with >>3). The tile the sprite is on is not the tile that I query in vram so I'm doing that wrong somehow.

I also tried to copy vram into an array and the step through it using SetTile to display each value. Again, seems as all the tiles are there but they appear in the wrong order.

How do you access a specific tile in the vram array based on pixel position values?
CunningFellow
Posts: 1488
Joined: Mon Feb 11, 2013 8:08 am
Location: Brisbane, Australia

Re: Collision and Vram

Post by CunningFellow »

OK, As a problem solving exersize please try this (TestTile is what ever number tile you want to use a ball, a brick. 1/4 or mario)

Here I am assuming that you are in video mode 3 where tiles are 8x8. In OTHER video modes that are not 8x8 the number "8" and the ">>3" are not correct

Test 1, Make sure the kernel is working as we expect a.

Code: Select all

VRAM[0] = TestTile;   // This should put a tile in the very top left of the screen
Test 2, Make sure the kernel is working as we expect b.

Code: Select all

VRAM[(0>>3)*VRAM_TILES_H + (8>>3)] = TestTile;   // This should put a tile in the very top of the screen and ONE cell off the left
Test 3, Make sure the kernel is working as we expect c.

Code: Select all

VRAM[(8>>3)*VRAM_TILES_H + (0>>3)] = TestTile;   // This should put a tile in the very left of the screen and ONE cell off the top
Test 5, Make sure the kernel is working as we expect d.

Code: Select all

uint8_t i;

for(i=0; i<100; i=i+8) {
    VRAM[(i>>3)*VRAM_TILES_H + (i>>3)] = TestTile;    // This should draw 12 tiles as a diagonal line FROM the top left corner down
}
Do these all produce the results writing directly to VRAM as expected?
User avatar
nicksen782
Posts: 714
Joined: Wed Feb 01, 2012 8:23 pm
Location: Detroit, United States
Contact:

Re: Collision and Vram

Post by nicksen782 »

I used the following code to try out your suggestion:

Code: Select all

	if(joy & BTN_SELECT){
	//ClearVram();
	//copyvramanddisplayit();
	//WaitVsync(12);
	//while(ReadJoypad(0) != BTN_START){}
	unsigned char TestTile = 18+RAM_TILES_COUNT;
	while(ReadJoypad(0) != BTN_A){}
	WaitVsync(12);
	ClearVram();
	vram[0] = TestTile;   // This should put a tile in the very top left of the screen
 	while(ReadJoypad(0) != BTN_A){}
	WaitVsync(12);
	ClearVram();
	vram[(0>>3)*VRAM_TILES_H + (8>>3)] = TestTile;   // This should put a tile in the very top of the screen and ONE cell off the left
	while(ReadJoypad(0) != BTN_A){}
	WaitVsync(12);
	ClearVram();
	vram[(8>>3)*VRAM_TILES_H + (0>>3)] = TestTile;   // This should put a tile in the very left of the screen and ONE cell off the top
	while(ReadJoypad(0) != BTN_A){}	
	WaitVsync(12);
	ClearVram();
	uint8_t i;

	for(i=0; i<100; i=i+8) {
		vram[(i>>3)*VRAM_TILES_H + (i>>3)] = TestTile;    // This should draw 12 tiles as a diagonal line FROM the top left corner down
	} 
	while(ReadJoypad(0) != BTN_A){}
	}
Results:
The first result has the tile at the upper left of the screen.
The second result has the tile one space lower than the first result.
The third result has the tile on the top row and on the 5th cell.
The fourth result draws a type of diagonal but probably not what was expected.
** See the attachment for screenshots of the results.

My goal is to read the tile that my character is standing on. Reading and writing shouldn't be all that different I figure.
Attachments
picturesvram.doc
(200 KiB) Downloaded 504 times
CunningFellow
Posts: 1488
Joined: Mon Feb 11, 2013 8:08 am
Location: Brisbane, Australia

Re: Collision and Vram

Post by CunningFellow »

Bizare

Looks like X is the higher order of the index. Thats not what the document you linked to says. I have never used the tile modes myself, but I can't imagine the documentation could be so wrong.

Please try

Code: Select all

uint8_t i;

for(i=0; i<100; i=i+8) {
    VRAM[(i>>3)*VRAM_TILES_V + (i>>3)] = TestTile;    // Changed the V and H positions
}
See if that makes the diagonal line.
CunningFellow
Posts: 1488
Joined: Mon Feb 11, 2013 8:08 am
Location: Brisbane, Australia

Re: Collision and Vram

Post by CunningFellow »

OK - I just tried the code you posted by cutting and pasting it in the "arkanoid" which uses mode 3

It produced the expected results for me.

So something else is funny happening at your end.

Have you started to scroll the screen or something else like that? The ((Y>>3)*H_size+(X>>3)) logic wont work on a screen that does not have it;s logical origin at 0,0
User avatar
nicksen782
Posts: 714
Joined: Wed Feb 01, 2012 8:23 pm
Location: Detroit, United States
Contact:

Re: Collision and Vram

Post by nicksen782 »

I am using Mode 3 with the scrolling turned on but I have not changed the scroll values at this point.

This code is pretty interesting. Screenshot included:

Code: Select all

unsigned char TestTile = 18+RAM_TILES_COUNT;
while(ReadJoypad(0) != BTN_A){}
	
	unsigned char x = 0;
	unsigned char y = 0;
	unsigned char thecount =0;
	for( y=0; y<32; y++){
		for( x=0; x<32; x++){
			vram[((y) * VRAM_TILES_H) + (x)] = TestTile;
			WaitVsync(1);
			//vram[((y) * VRAM_TILES_H) + (x)] = TestTile;
			//if(thecount==255){thecount=0; TestTile+=9;}
			//else{thecount++;}
		}
	WaitVsync(20);
	TestTile+=1;
	}
It seems to draw each tile starting from the 0,0 origin downward. Once 8 tiles are drawn it goes back to top row, moves right and then draws another 8 tiles downward. I used a different tile for each set of 32.

These are the KERNEL_OPTIONS for my Makefile:

Code: Select all

## Kernel settings
KERNEL_DIR = ../../../kernel
KERNEL_OPTIONS  = -DVIDEO_MODE=3 -DINTRO_LOGO=0 -DSOUND_CHANNEL_4_ENABLE=0 -DSCROLLING=1 -DSOUND_MIXER=1
KERNEL_OPTIONS += -DMAX_SPRITES=5 -DSCREEN_TILES_V=27 -DRAM_TILES_COUNT=1
#
#-DFIRST_RENDER_LINE=24 
KERNEL_OPTIONS += -DVRAM_TILES_V=32
Attachments
uzem_000.png
uzem_000.png (38.12 KiB) Viewed 7520 times
CunningFellow
Posts: 1488
Joined: Mon Feb 11, 2013 8:08 am
Location: Brisbane, Australia

Re: Collision and Vram

Post by CunningFellow »

OK.

I am out of my depth here I think. That doesn't make sense to me.

Maybe enabling scrolling changes the VRAM layout.

As I said earlier I have only ever used mode-6 (which I modified the way VRAM works to be faster) and made my own totally custom mode. I have never used any of the tile modes apart from just a hour or so ago to test the code discussed here.

I will have to defer to Uze or someone else with more experience than me to explain that.

If you include a complete ZIP of your project directory I can single step the ASM. I am comfortable with that kind of thing.
User avatar
uze6666
Site Admin
Posts: 4821
Joined: Tue Aug 12, 2008 9:13 pm
Location: Montreal, Canada
Contact:

Re: Collision and Vram

Post by uze6666 »

Hi guys,

Video mode 3 *with scrolling* (that's what you specified in your makefile) uses a weird, non-linear VRAM organization as explained in mode 3's docs. Hence one must use the t(x,y)=vram[((y>>3)*256)+8x+(y&7) formula to address the VRAM. Moreover do not forget to add the linker flag as described in this section or your screen will most probably be garbled.
I also understand that in mode 3 that the first tiles in this array are the ram tiles.
To be more precise, all entries in this array are indexes to some tiles. For the mode 3 video engine, it's the index position that defines if it's a ramtile or a flash tile. So if RAM_TILES_COUNT=10, vram[0]...vram[9] will identify a tile in RAM while vram[10]...vram[255] will identify tiles in FLASH. So this is why more you have ramtiles less you can have unique flash tiles on screen.

Out of curiosity, what's the reason you need a "GetTile()" function in your game? If it has potential for reuse I could just add one in mode 3.
Post Reply