hopefully my last Mappy related question..this time, collision detection
red-dragon

Hi Peoples,
Ok, so I'm trying to implement mappy collision detection. Right now I have a damn ugly map, with 4 borders. These borders, Link shouldn't be able to walk on. The top and bottom borders are made of the exact same ugly grey tile, and left and right borders are made of some ugly brown tile.

So, for those two tiles, I opened this 'map' in Mappy, double-clicked on each of the two tiles, and set all 4 flags for collision detection. To my understanding, they are tl, tr, bl, and br.

So, I have this code within my program:

int collided(int x, int y)
{
   BLKSTR *blockdata;
   blockdata = MapGetBlock(x/mapblockwidth,
                   y/mapblockheight);
   return blockdata->tl;
}

So before Link walks N, S, E, W, I check for collision with the above code. If above code returns false, as in, no flags have been set, then Link can move in that direction. So, here's relevant code:

1switch(dir)
2 {
3 //west
4 case 1:
5 if(!(collided(link->x - num1, link->y)))
6 link->x -= num1;
7 break;
8
9 //north
10 case 2:
11 if(!(collided(link->x, link->y-num1)))
12 link->y -= num1;
13 break;
14
15 //east
16 case 3:
17 if(!(collided(link->x + num1, link->y)))
18 link->x += num1;
19 break;
20
21 //south
22 case 4:
23 if(!(collided(link->x, link->y+num1)))
24 link->y += num1;
25 break;
26...
27}

This seems really simple. This works for top and left border, but NOT for the right and bottom borders. Maybe I've misunderstood the flags...? Can someone please help me understand what I might be doing wrong? TIA.

p.s. Two semi-weird problems I'm experiencing using mappyal. One, if map is made of 8bit tile, and I hit esc, I exit fine. If I'm using a 24bit one, when I exit by hitting esc, I get an error message. Second problem is.. I've set my Link sprite's background color to magenta (r=b=255, g=0) for transparency. Yet, when program runs, the magenta part switches from all black to weird lines. Any explanations?

Onewing
Quote:

This works for top and left border, but NOT for the right and bottom borders.

I noticed your collided function only returns blockdata->tl and tl means top left, so setting all the flags (tr, bl, br) won't help if you're only checking tl.

red-dragon

Hey Onewing,
I forgot to mention that I changed the code for collided() to:

int collided(int x, int y)
{
   BLKSTR *blockdata;
   blockdata = MapGetBlock(x/mapblockwidth,
                   y/mapblockheight);
   return (blockdata->tl && blockdata->tr && blockdata->bl && blockdata->br);
}

Either way though, even if i just check tl, and the flag is set for that block, shouldn't the code still work?

Even with above modified collided(), Link walks over right and bottom border. C'mon, gimme more ;)

Onewing

nm :-X

James Stanley

Shouldn't you really check which one it is? Or at least use || because if it collides on tl only, then

(blockdata->tl && blockdata->tr && blockdata->bl && blockdata->br)

becomes

(1 && 0 && 0 && 0)

which means 0...

With OR it returns 1. I dunno. I don't really understand your map engine.

TeamTerradactyl

Unless "blockdata->tl" means that the part of the map that is being evaluated returns NO "flags which depict that the tile cannot be moved onto". In that sense, it would correctly return:

return (0 && 0 && 0 && 0);

if the block was "free" to move onto. That would make sense with the function's name, as if (collided(this_x, this_y)) should return FALSE before the player's sprite is moved onto that position...

At least, that's how I understand the function :-)

EDIT: Oops, after re-reading my own post, I see what you meant about && instead of || there... my bad. You're right, sorry.

red-dragon

James,
You're right. Obviously wasn't thinking things through carefully last night.
The map is something like this (keep in mind, GB = Grey Tile Border, BB = Brown Border):

GBBBBBBBBBBBBBGB
GBxxxxxxxxxxxxxxGB
GBxxxxxxxxxxxxxxGB
GBxxxxxxxxxxxxxxGB
GBxxxxxxxxxxxxxxGB
GBxxxxxxxxxxxxxxGB
GBBBBBBBBBBBBBGB

GB and BB are the only tiles used for the 4 borders. All four collision flags were set for both.

I think you get the point. So, Link should not step on GBs or BBs (he can walk where the x's are). Just the square/rectangle area within. So, if any bits of those tiles have been set, i.e.
if(block->tl || tr || bl || br)
then don't move Link, Link stays where he's at.

So, should this pseudocode work for all 4 borders?

Onewing

When you say, "link can move over the right and bottom borders" do you mean he can walk right through and into the empty space beyond or that he can walk atop of the blocked border and then he seems to run into a wall. I say this because you check if linx->x + num1 has a collision flag set, but that x represents his far left coordinate. Thus, you should check link->x + link->width + num1 is collided. Same concept with the bottom border.

red-dragon

Onewing, I meant Link walks over those tiles. He does not move beyond the end of the map/screen; that part is ok. He just walks over/on top of the GB and BB tiles to the right and bottom.

Neil Walker

Hello,
I think those well minded people above are getting mixed up with what the flags actually do :)

The tl/tr/br/bl flags are not used by the mappy engine, they are just user defined flags that you use for your own purpose that you can set for each tile in your map.

As far as I can see your code is fine you need to trace into the switch to see why it isn't working. Can it be something simple like it is working, just you think it isn't because of the x/y position of your sprite?

Regaring the ESCape key, mappy is just a tile engine and doesn't process keyboard input, check your code :)

Regarding the sprite, are you loading them up before calling set_colour_depth() ?

red-dragon

Hi Neil
Thanks for clearing some things up. Right before I was about to put up more questions, I believe I've figured out what's going on, yay!

I THINK... when I move Link down and pass in his x,y coords, they are topleft of the sprite. I needed to do something to this effect:
oldy = link->y + 30;
link->y += num1;
res=collided_bottom(link->x, oldy);
if(res)
link->y -= num;

p.s. 30 is size of sprite. heh, does anyone understand what I'm babbling about here? If not, I'll give another shot at an explanation tomorrow morning :)

EDIT:
I am still having the weird transparency problem. My dude still appears with a black background sometimes and sometimes weird lines. Neil, no, the color depth is set first, the the loading of frames. Can you shed some light into why it matters to have one before the other?

Neil Walker

hurrah, I got a question right for once ;)

Regarding the sprite transparency/background problem, perhaps it's time to post your code as an attachment, if it isn't too large :)

As for the '30' thing you should never hard code values like this, either use link->h or assign the height to a variable.

If you need any further help with mappy or collisions you can always check out my mappy tile map tutorial (see sig and select 'tutorial' from the menu)

red-dragon

Hey Neil!
Ok, i'm posting a zip file. Download, compile and run. Note though: collision detection code is not implemented yet. I believe the two functions for setting up are right before main starts. I appologize ahead of time for not having clean code.
If you move Link around, you'll see the issue I'm speaking of. I believe he's 24-bit, and map is 8bit.

Here is the file.

p.s. I will replace the 30, don't worry ;)

Neil Walker

Hello,
Your problem is quite simple and one that probably catches most people out for the first time.

BITMAP *temp = create_bitmap(width,height);
masked_blit(source,temp,x,y,0,0,width,height);

What this means is you are creating a bitmap and blitting only the non magenta stuff to it, i.e. only link character.

Firstly the odd problem with the random black/white background of link: when you create a bitmap, the memory it is allocated contains random data and so when you masked blit the background noise is still there.

For every bitmap you create you should always do a clear() or clear_to_color().

So, if you change the code to this:

BITMAP *temp = create_bitmap(width,height);
clear(temp);
masked_blit(source,temp,x,y,0,0,width,height);

the noise disappears, but you'll then discover the another problem in that the noise has gone but link has a completely black background, which was hinted at above, i.e. you are only masked blitting link, which means you are losing your magic pink :)

So, either change it to clear_to_color(temp,makecol(255,0,255)), or probably better, simply change masked_blit to a blit() only and all is well :)

i.e. change your code to this:

blit(source,temp,x,y,0,0,width,height);

But remember for the future the problem with not clearing bitmaps :)

red-dragon

Neil Walker,
You were right; I have changed it to blit() now and Link appears as he should. Thanks loads man, the reason makes sense.

I'm hoping that you (or anyone else!) out there can help me once again.

I thought I'd be okay with collision detection. For instance, my collide_right function check to see if tr and br bits are set. But this isn't enough...

If Link's head is on a tile grass and say he's walk to the right...Now from waist down, he encounters brown tile.

I.e. Below: g is for grass tile and b is for brow tile.
0->gggggg
1->gggggg
2->gbbbbb

Suppose Link is coming from right but he's positioned between rows 1 and 2 such that his head his g and his legs hit b. So if we're going right and this is the case, the code goes "check for tr or br bits of tile" and since Link's head is hitting grass tile, it sees that those bits are not set.. so he appears to walk over half green and half brown.

If this explanation makes no sense, please check out my code/executable and make Link move to the brown part if you go down.

Anyway..... so how do I anticipate for this? How do I code collision detection for something like this? TIA.

p.s. Neil, again, thanks man.

Thread #588658. Printed from Allegro.cc