News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_EgoTrip

[CPCtelera] Collisions with Tiles

Started by EgoTrip, 17:56, 02 November 15

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

EgoTrip

How do I detect collisions with tiles?

I have an array screens[32][20] with the 2x8 tiles. I dunno what I'm doing wrong but I cant seem to get my player to collide with them properly. I've tried things like

(cpct_isKeyPressed(Key_CursorRight) && x < (SCR_W - SP_W) && screen[(x+4)/2][y/8]<16 )

and its equivalent for the other three directions but it either runs into the wall, or stops short of the wall. Also it only seems to recognise a 2 byte x 8 pixel block (8*8 in MODE 1) for 4x16 blocks in the middle of the play area. Floor/walkable tiles are the first 16 (hence <16 on the screen array), the rest are wall tiles.

Any help would be appreciated.

FloppySoftware

Quote from: EgoTrip on 17:56, 02 November 15
How do I detect collisions with tiles?

I have an array screens[32][20] with the 2x8 tiles. I dunno what I'm doing wrong but I cant seem to get my player to collide with them properly. I've tried things like

(cpct_isKeyPressed(Key_CursorRight) && x < (SCR_W - SP_W) && screen[(x+4)/2][y/8]<16 )

and its equivalent for the other three directions but it either runs into the wall, or stops short of the wall. Also it only seems to recognise a 2 byte x 8 pixel block (8*8 in MODE 1) for 4x16 blocks in the middle of the play area. Floor/walkable tiles are the first 16 (hence <16 on the screen array), the rest are wall tiles.

Any help would be appreciated.

Hi EgoTrip,

I understand the expression you wrote is inside an if, and this part is referred to the tile the player want to go:

screen[(x+4)/2][y/8]

I think the problem is there.

You should print and check the row / column calculations for the array, and see if they are legal or not. May be they are out of range, you kown, and that could cause unpredictable behaviour.
floppysoftware.es < NEW URL!!!
cpm-connections.blogspot.com.es

arnoldemu

To do correct tile collision you need to know:

1. the width of your sprite
2. the x coordinate of your sprite (assuming this is the top-left of the sprite)
3. the height of your sprite
4. the y coordinate of your sprite (assuming this is the top-left of the sprite)
5. the width of a tile (assumes all tiles the same width)
6. the height of a tile (assumes all tiles the same height)

Now the condition depends on the direction you are moving.

for moving left:

- you need to consider the x coordinate only because it's on the leftmost side.
- you need to know what the x coordinate should be *before* you move into the next tile to the left.
- you need to convert that x coordinate into a tile coordinate.
- then you can check the map for the tile immediately to the left of this

if the tiles are 4 pixels wide, these are the x coordinates for moving left:

0 4 8 12 16 etc

moving 1 more pixel to the left moves the sprite into the next tile to the left.

So if you are at 1,2,3 then you are still moving in the first tile.
5,6,7 you are still moving in the second tile.

We are really interested in the "offset" in the tile, i.e. 0-(tile_width-1)
To calculate this we need the *remainder* and in C we get the remainder with %.
Then to convert pixel coordinates to tile coordinates we use an integer divide. a divide with no remainder giving a integer number.

so the condition is:

if (
/* pressing left cursor */
cpct_isKeyPressed(Key_CursorLeft) &&
/* at leftmost position in current tile; remainder is 0 */
((x%tile_width)==0) &&
/* convert coordinates into tile x,y and lookup in screen (NOTE -1 on x to the tile to the left */
screen[(x/tile_width)-1][y/tile_height]<16)
)
{
}


for moving right:
- you need to consider the coordinate of the rightmost pixel of your sprite because it's on the rightmost side
- you need to know what that coordinate is *before* you move into the next tile to the right.
- you need to convert that coordinate into a tile coordinate.
- then you can check the map for the tile immediately to the right of this

For moving right, we need to consider the right pixel of the sprite, this is:

(x+(sprite_width-1))

We then need to see if this is at a position where you would move into the next tile to the right.
for a tile of width 4 this is:

3 7 11 etc.

if we look at the remainder it is (tile_width-1).


if (
/* pressing right cursor */
cpct_isKeyPressed(Key_CursorRight) &&
/* at rightmost position in current tile */
*((x+(sprite_width-1))%tile_width)==(tile_width-1))
/* convert coordinates into tile x,y and lookup in screen (NOTE +1 on x to the tile to the right */
screen[(x/tile_width)+1][y/tile_height]<16)
)
{
}

and that will work.

the only problem is if your sprite is not rectangular it can look like your not
getting close enough. either redesign your sprite or accept it.

it is often best to  think of it as rectangular because it makes it all much easier.


My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

EgoTrip

Well I changed it slightly to this:

      dx=(x/2);
      dy=(y/8);

      if      (cpct_isKeyPressed(Key_CursorRight) && x < (SCR_W - SP_W) && screen[dx+2][dy]<16 )
{ ... code ... }


It moves around fine but  it wont go right up to the wall, 4 pixels away. So I changed right and down to dx+2 and dy+2 respectively and this fixes that part but I can't figure out how to make it move properly going up and left. Incidentally the 16x16 blocks in the middle of the screen are recognised now, but again, can only go within 4 pixels left and up.

Fessor

#4
Define Pixel. You have to take into Account that a Mode 0 Pixel is 4 Pixels wide and 2 Pixels tall.
Even if the Resolution is 160x200, the coordinate Sytem ranges to 640x400....

What are the max values of x and y?

I think it must be x/8 and y/16 to get to an array cell.

arnoldemu

#5
following on from my code. if the tile width is a power of 2 (e.g. 2 4 8 16 32 etc ) then:

% tile_width becomes & (tile_width-1)
and the / can become the appropiate shift (/2 -> >>1, /4 >>2, /8 >>3).
This can make it faster.

for left you may want to add this check:

((x/tile_width)>0)

to make sure when you are at tile 0 you don't check a negative position

and (x/tile_width)<(map_width-1) for right.

edit: if all values are pixels, or all values are byte coordinates it doesn't matter because they are consistent. if one is pixels and one is byte coordinates then some conversion is needed.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

@EgoTrip: you are randomly putting in numbers until it works. that will lead to frustration and it not working all the time.

please look at my post and understand the numbers.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

Quote from: EgoTrip on 20:31, 02 November 15
Well I changed it slightly to this:

      dx=(x/2);
      dy=(y/8);

      if      (cpct_isKeyPressed(Key_CursorRight) && x < (SCR_W - SP_W) && screen[dx+2][dy]<16 )
{ ... code ... }


your dx here is converting pixel coordinates of the *left* side of the sprite into a tile coordinate. I assume here 2 is the width of your tile in pixels.

your dy here is converting pixel coordinates of the *top* side of the sprite into a tile coordinate. i assume here 8 is the height of your tile in pixels.

your key check is fine, your check for if the sprite will go to far to the right is fine.

screen[dx+2][dy]<16 )

this looks like it is looking two tiles to the right? two?
is your sprite exactly one tile wide? (one tile for the sprite, 1 for the tile next to it??)

<16 you already described it's your tile numbers and the meaning you give to
these.

the code here assumes you are moving an exact tile every press of the key, very chunky. the (dx/2) is a integer number, so it is rounding the value, it looses the fineness of the value.

if you want to check the left, then it's dx-1??

please tell us what the numbers are otherwise we're just guessing and we can't give you the correct answer!
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

EgoTrip

Quote from: Fessor on 20:40, 02 November 15
Define Pixel. You have to take into Account that a Mode 0 Pixel is 4 Pixels wide and 2 Pixels tall.
Even if the Resolution is 160x200, the coordinate Sytem ranges to 640x400....

What are the max values of x and y?

I am using Mode 1, and 4 pixels as in 1 byte. I am moving around the screen in 4 pixel increments. Max x and y is x = 64 bytes, y = 160 pixels. This is how CPCtelera's sprite routine works, bytes for x and pixels for y as they are the same as bytes.

I changed the code to this in order to calculate before it moves:
if      (cpct_isKeyPressed(Key_CursorRight) && x < (SCR_W - SP_W))
        {
        dx=x+1;
        dy=y;
        if (screen[dx/2][dy/8]<16){


But now it moves to the left and top edges fine but goes through the first 8 pixels of the right and bottom walls. The 16x16 blocks are not fully recognised again.

Fessor

Ah.. ok..
SP_W = Sprite Width, also in Bytes?



EgoTrip

Quote from: Fessor on 21:12, 02 November 15
Ah.. ok..
SP_W = Sprite Width, also in Bytes?

Yes, SP_W = 4 and SP_H = 16

FloppySoftware

#11
Debug a bit the variables, showing their values. Something is wrong with the x & y calculations.

Edit: Wait, is this correct?

x < (SCR_W - SP_W)

Or may be the right expression would be:
x < SCR_W

For example:

Values of x are 0, 1, 2, 3... 15
Values of SCR_W is 16.

Same for y and SCR_H.
floppysoftware.es < NEW URL!!!
cpm-connections.blogspot.com.es

Fessor

#12
Hmmm.... The formula at the first post looks then nearly correct...

It must be an offset-error. Array with [32][20] goes from 0..31 and 0..19


*edit*

(cpct_isKeyPressed(Key_CursorRight) && x < (SCR_W - SP_W) && screen[((x+4)/2)-1][(y/8)-1]<16 )

EgoTrip

Quote from: Fessor on 21:37, 02 November 15
Hmmm.... The formula at the first post looks then nearly correct...

It must be an offset-error. Array with [32][20] goes from 0..31 and 0..19

x and y are the top left of the sprite, which is 16x16 pixels, or 2x2 tiles size. So I can understand why its moving a tile too far to the right however if I do it two tiles to the right it doesn't work properly. I'm completely lost as to why its not working the way it should do. Going left and up works fine with my new code but going down and right does not. I've tried a few different methods and just end up with no real working results.

x and y are always in multiples of 4, so there should be no issues with any remainders.

SCR_W and SCR_H are 64 and 160 respectively.

arnoldemu

#14
EDIT: updated code.
Check if key is pressed.
Then check condition. here I check to see "no move".
else I do movement because key is pressed

Using "magic" numbers is never good. I like to #define the magic numbers so I can write nice equations.


#define SP_W 4 /* 4 bytes - 16 pixels */
#define SP_H 16
#define XINC 1 /* 4 pixels - 1 byte */
#define YINC 4
#define MAXX 64 /* 64 bytes wide - 256 pixels wide */
#define MAXY 160
#define TH 8
#define TW 2 /* 2 bytes - 8 pixels wide */

/* check to left */
/* key is pressed, x coordinate doesn't go off left of screen,
at left edge of tile, and tile map says we can move */
if (cpct_isKeyPressed(Key_CursorLeft))
{
  if (x>0) && ((x%TW)==0) && (screen[(x/TW)-1][(y/TH)]<16))
{
}
else
{
     x-=XINC;
}
}

/* check above */
/* key is pressed, y coordinate doesn't go off top of screen,
at top edge of tile, and tile map says we can move */
if (cpct_isKeyPressed(Key_CursorUp))
{
  if ((y>0) && ((y%TH)==0) && (screen[(x/TW)[(y/TH)-1]<16))
{
}
else
{
     y-=YINC;
}
}

/* check right */
/* key is pressed, x coordinate doesn't cause us to go off the right side of screen,
at top edge of tile, and tile map says we can move */
if (cpct_isKeyPressed(Key_CursorRight))
{
  if ((x<(MAXX-SP_W)) && ((x+SP_W-1)%TW)>=(TW-XINC)) && (screen[(x/TW)+1][(y/TH)]<16))
{
}
else
{
     x+=XINC;
}
}

/* check below */
/* key is pressed, y coordinate doesn't cause us to go off the bottom of screen,
at top edge of tile, and tile map says we can move */

if (cpct_isKeyPressed(Key_CursorDown))
{
if ((y<(MAXY-SP_H)) && (((y+SP_H-1)%TH)>=(TH-YINC)) &&   (screen[(x/TW)[(y/TH)+1]<16))
{
}
else
{
    y+=YINC;
}
}
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

you have remainders:

- x movement is 4 pixels or 1 byte at a time.
- tile width is 2 bytes wide.
- your tile size is different to your sprite size.

If you want no remainders, make everything the same size. tiles and sprites and movement, then no remainders ;)

at x = 0, we are in first tile (our x,y coordinates)
at x = 1, we are still in first tile (but 4 pixels away from it's left).
at x = 2, we are now in second tile (our x,y coordinates).
at x = 3, we are still in second tile (but 4 pixels away from it's left).
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

EgoTrip

Nope can't figure it out or get it working. I know I'm wasting my time with this.

FloppySoftware

#17
EgoTrip,

You said this:

"x and y are always in multiples of 4, so there should be no issues with any remainders."

But arnoldemu is right, that's not true.

You have to use x and y coordinates referred to tiles positions (that are equal to the position in the array), not screen ones.

Then, you can use multiplications (or similar) to convert the tile coordinates into a screen position.

And it's best to have equal sizes for sprites and tiles. That helps a lot!




floppysoftware.es < NEW URL!!!
cpm-connections.blogspot.com.es

EgoTrip

It doesn't help at all it just confuses me. It would also help if CPCtelera had tile routines for 16x16 mode 1 pixel tiles. All this bytes and coordinates bullshit, everyone tells me something different. I'm too much of a retard for this anyway so I think the best thing to do is just completely delete everything from my computer and forget about it.

FloppySoftware

Oh, well... that's the easy way!  :o

But it's not the best, for sure.  :'(
floppysoftware.es < NEW URL!!!
cpm-connections.blogspot.com.es

arnoldemu

Quote from: EgoTrip on 23:41, 02 November 15
It doesn't help at all it just confuses me. It would also help if CPCtelera had tile routines for 16x16 mode 1 pixel tiles. All this bytes and coordinates bullshit, everyone tells me something different. I'm too much of a retard for this anyway so I think the best thing to do is just completely delete everything from my computer and forget about it.
@EgoTrip:
It can take time to understand. I had to work this method of collision out too when I had the same problems as you. Sometimes I find it good to sit down with paper and draw it out. Draw the grid, the sprite, it's positions of what it should look like before and after what I wanted, draw it to scale and put numbers to it. I think this could work better for you because your talents are more visual. It may suddenly click!!

Sure programming is your weak area. Mine is graphics and sound! I can make some passable graphics, I could also make some basic music, but for me it is hard work and not easy at all.

I know programming is your weakest. Giving up and deleting it is only going to make more anger and fix in your mind that you can't do it. I think you make progress every day.

Your using cpctelera and your trying! That is one step closer.

I know a game maker would be ideal, but it would take a programmer a long time to make a good game maker which has very few bugs and which is flexible enough for what you want. The best is to hope for a conversion tool from an existing one, but that is also takes a lot of time and effort. So the sad thing, is that you may need to keep on pushing yourself and you'll get there.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

Fessor

#21
As Arnoldemu says, visualisation helps a lot.

01|23|45|67|89|AB|CD|EF   x-coordinate, bytes (x from 0..15)
00|01|02|03|04|05|06|07   tile-cells, two bytes (cells from 0..7)
    |SP|SP|    |xx|    |    |       Sprite, four bytes, at x=2. x+sp_w=6. Division by two = 3, Tile in Cell 3 is walkable; movement to the right is allowed.
    |  S|PS|P  |xx|    |    |       Sprite, four bytes, now at x=3. x+sp_w=7. Division by two may get the 3.5 rounded to 4. Odd Positions should masked out at condition checks by AND #0xfe
    |    |SP|SP|xx|    |    |       Sprite, four bytes, now at x=4. x+sp_w=8. Movement to the right is disallowed as the tile in cell 4 is not walkable.

xx = nonwalkable tile
SPSP = four bytes of the Sprite



EgoTrip

Quote from: arnoldemu on 08:26, 03 November 15
@EgoTrip:
It can take time to understand. I had to work this method of collision out too when I had the same problems as you. Sometimes I find it good to sit down with paper and draw it out. Draw the grid, the sprite, it's positions of what it should look like before and after what I wanted, draw it to scale and put numbers to it. I think this could work better for you because your talents are more visual. It may suddenly click!!

Sure programming is your weak area. Mine is graphics and sound! I can make some passable graphics, I could also make some basic music, but for me it is hard work and not easy at all.

I know programming is your weakest. Giving up and deleting it is only going to make more anger and fix in your mind that you can't do it. I think you make progress every day.

Your using cpctelera and your trying! That is one step closer.

I know a game maker would be ideal, but it would take a programmer a long time to make a good game maker which has very few bugs and which is flexible enough for what you want. The best is to hope for a conversion tool from an existing one, but that is also takes a lot of time and effort. So the sad thing, is that you may need to keep on pushing yourself and you'll get there.

Can I see your code and can you explain it to me please? I'm still nowhere near to understanding it which is really doing my head in. Because so far I have managed to get the character moving, along with two bouncing enemies who all interact with each other. I also figured out how to draw the tile map and a few other things. But this has me completely stumped. I really am close to completely giving up.

Singaja

I have one suggestion EgoTrip. Apart from drawing the tiles you could print an additional debug text on screen with actual values, it could give you a picture what's going on. That's how I work professionally more or less in software development. You could even have some debug info for each tile for double checking.

EgoTrip

FINALLY! Done it. Hopefully. All seems to work now but let's wait and see before I get carried away, however everything seems good.

Powered by SMFPacks Menu Editor Mod