gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Beginners > Collision help?

#97329 - lostgame - Wed Aug 09, 2006 7:07 am

Again, I have a small ball ('char' in this case), in which I want to collide with solid blocks.

I declared an array with several x and y coordinates for blocks.

Code:
u16 blockx[5] = {40,64,80,104,128};
u16 blocky[5] = {32,128,64,96,16};


I ask if the ball(char), is in the collision by returning a value, 'canmove'.

Code:
while(1)
   {
   u8 a;
   
   for (a=1; a<=5; a++)

   {
           if( (col(blockx[a]+1,blocky[a]+1,8,8,xchar,ychar,16,16))==1  ||  (col(blockx[a]-1,blocky[a]-1,8,8,xchar,ychar,16,16))==1 )
                canmove=0;

           else

         canmove=1;
         
   }

   if(canmove=1){
      Movechar();
      MoveSprite(&sprites[0],xchar,ychar);
   }

      
      WaitForVsync();
      CopyOAM();
   }


As you can see, I wrote a method called 'col', which is here:

Code:
int col(int o1x,int o1y,int o1w,int o1h,int o2x,int o2y,int o2w,int o2h)
{
  if (o1x+o1w > o2x && o2x+o2w > o1x && o1y+o1h > o2y && o2y+o2h > o1y)
    return 1;
  else
    return 0;
}


It makes so much sense it hurts, yet, predictably, fails.

The ball goes straight through the blocks, like they're not even there.

What's going on?

#97330 - sajiimori - Wed Aug 09, 2006 7:23 am

Array indexes in C start with 0, not 1. The maximum index of an array with 5 elements is 4.

Every pass through your 'a' loop is writing a value to canmove. That means every pass except the last one is useless.

Simplify your code by carrying x,y pairs in structs instead of separately.
Code:
struct Vector
{
  u16 x;
  u16 y;
};

struct Vector blocks[] =
{
  { 40, 32 },
  ...
};

Write an isSolid function that takes a position and returns true if it's filled by a block.
Code:
bool isSolid(const Vector* v);

That will make your task simple.

Needless to say, this post doesn't cover everything there is to be said. It just covers the most crucial things for starters.

#97352 - Optihut - Wed Aug 09, 2006 11:36 am

"if(canmove=1)"

This should either be "if (canmove)" or "if (canmove==1)". Right now it assigns the value 1 to the variable canmove and is always true.

#97393 - dj-ceejay - Wed Aug 09, 2006 3:38 pm

An easy mistake to make if you've come from another language like BASIC.
_________________
Fruit Machine Games:
http://www.fmsoftware.info/

#97398 - lostgame - Wed Aug 09, 2006 4:06 pm

Okay, now I have another problem.

That code makes it so if it sees collision anywhere, it can't move at all-even in the opposite direction of the block it's colliding with.

sajiimori, I fixed that array index problem, and Optihut, I also fixed the "canmove" variable.

Like I said, it works-but as soon as you hit it, from any side, the character won't move anymore.

Also, like sajiimori said, it's only hitting the last block and i'm not sure what I'm doing wrong.

#97407 - Optihut - Wed Aug 09, 2006 4:42 pm

lostgame wrote:
Also, like sajiimori said, it's only hitting the last block and i'm not sure what I'm doing wrong.


The "else" command overwrites canmove during the execution of the loop when the condition is not met.
So you need to exit the for loop when canmove is set to 0. IIRC, this can be done with "break;"
Alternatively you could remove the "else" part and write "canmove = 1;" before the for loop.

As for no movement at all, I guess you could use another variable to store the direction of the collision in order to program something that would allow you to still be able to move in the opposite direction.

#97422 - dj-ceejay - Wed Aug 09, 2006 5:44 pm

Another reason we need a reliable debugging with code step through for GBA & NDS.
_________________
Fruit Machine Games:
http://www.fmsoftware.info/

#97426 - lostgame - Wed Aug 09, 2006 6:07 pm

Optihut wrote:
lostgame wrote:
Also, like sajiimori said, it's only hitting the last block and i'm not sure what I'm doing wrong.


The "else" command overwrites canmove during the execution of the loop when the condition is not met.
So you need to exit the for loop when canmove is set to 0. IIRC, this can be done with "break;"
Alternatively you could remove the "else" part and write "canmove = 1;" before the for loop.

As for no movement at all, I guess you could use another variable to store the direction of the collision in order to program something that would allow you to still be able to move in the opposite direction.


*phew*

This is much more complicated than I thought...

In a bit, I will upload all the code so you can see where I've screwed up.

#97435 - sajiimori - Wed Aug 09, 2006 7:05 pm

Lostgame, one thing to consider is what "canmove" means to you. To me, it sounds like if it's false, the thing can't move at all.

What you probably want is to know whether an object can move to a particular place.

If you're satisfied with the definition that an object can move to a place if that place does not overlap anything solid, then the isSolid function is all you need.
Code:
void tryMove(Vector* myPos, const Vector* dest)
{
  if(!isSolid(dest))
    *myPos = *dest;
}

#97496 - lostgame - Thu Aug 10, 2006 4:14 am

Alright, thanks you guys, with a little bit of my previous game coding knowledge, I was able to get it to work.

First off, I fixed the actual collision checking statement, which, in and of itself, was fundimentally flawed.

Here's what it looks like now:
Code:
if (o2x+o2w > o1x && o1x+o1w > o2x && o2y+o2h > o1y && o1y+o1h > o2y)


Then I added a prevx and prevy variable, and we all know how that works.

I am working on making the blocks load from seperate files, like levels, so far I modified it so it has a structure that loads the following values:

x,y,width,height,tile_number,solid

My plan is to have these files read from an external file. I will then develop a little program for Windows in C++ that will allow you to design your own levels based on a simple tile placement method, assigning these values as you go.

For the time being, it will simply be in an external file such as ".lev". I will make a block that if you touch, it will move to the next level.

*sighs*

Thank you for all your help, now that I have passed the major stumbling block, I know most everything else I will need to know.

Thanks again, guys, I'm happy to be back in the Game Boy Advance development scene.

Expect a demo within the week!

*insert retarded smiley here*

=P

#97514 - Ultima2876 - Thu Aug 10, 2006 6:17 am

Same lostgame from sws2b? =p

#97592 - lostgame - Thu Aug 10, 2006 5:58 pm

Yes. =P

#98090 - lostgame - Sun Aug 13, 2006 5:11 am

Sorry for the double post, I just had news and an edit doesn't show the "new stuff" icon.

I put it all into a struct, added gravity, proper collision and a camera for scrolling. You can now walk along the tops of the blocks, and jump from block to block.

Basically, I have a [very] simple platforming engine. JJFtails of SWS2B has also assisted.

#98117 - Optihut - Sun Aug 13, 2006 10:07 am

Great to hear you're making progress! My own game making ambitions are still in the planning stages, unfortunately.

#98149 - lostgame - Sun Aug 13, 2006 5:19 pm

Thanks, Optihut!

My only concern is memory management.

Is there any way to see how much of the GBA's RAM and procesor is being used in VisualBoyAdvance?

#98150 - tepples - Sun Aug 13, 2006 5:34 pm

You can see how much processor is being un-used by using the VCOUNT register, one of the GBA's built-in timers. Read VCOUNT before and after your VBlankIntrWait() call, subtract them, and write the result to the screen.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#98157 - sajiimori - Sun Aug 13, 2006 7:13 pm

There might be an easy way to check static EWRAM usage in DevKitARM, but I don't know much about it, so one hack that's likely to work is calling malloc at the beginning of main (then freeing the allocation). I'd expect the address of the block to be the end of the static allocations.

Checking dynamic EWRAM usage (again, with no DevKitARM knowledge) basically involves wrapping malloc/free with your own functions that keep track of how much is currently allocated.

Checking stack usage is easy: Make a function that has a single local variable, take its address, and that's the top of the stack.

Some knowledge of DevKitARM is required to check static IWRAM usage. If the linkscript produces a symbol at the end of the static allocations, you can declare it (as anything, like an int) and take its address to find how much is being used. I'd expect the linkscript to produce such a symbol, but I don't know what the author called it.

#98162 - keldon - Sun Aug 13, 2006 7:40 pm

Hmmm, that technique may not work because if you first allocate X bytes, and then later free it, then who is to say that the next allocated piece of memory will not be placed there.

They could use a round robin type allocation but it is still not definate. And there is still the chance of the next allocation is not at the end of the memory.

But you can make a define that will call your own malloc/free function instead in your debug mode that will count the size of the allocations. And what you can do to keep track of the data size for when you free memory is to store an extra 2 bytes before your allocation with the size, and get your malloc to return the byte after that.

Or maybe there is another way, and maybe your memory usage may allow sajimori's suggestion to work without any problems.

#98185 - sajiimori - Sun Aug 13, 2006 11:08 pm

I don't understand your objection. I'm just talking about making one allocation at startup, then freeing it, just to find out where the beginning of the heap is, which is virtually always at the end of the static data section (for the region that contains the heap, which is EWRAM for most configurations).

Or are you objecting to the method of tracking dynamic allocations?

Edit: Upon re-reading your post, it's more clear that you're objecting to my method of tracking dynamic memory usage. I'm not sure what you think is wrong with it, since all I suggested was wrapping malloc and free. Since I didn't suggest a mechanism for doing the actual tracking, it makes little sense to say the unspoken mechanism doesn't work. ;)

Anyway, if you're going to prefix your allocations with a size, you'd better make it a multiple of 4 bytes.

#98189 - keldon - Sun Aug 13, 2006 11:44 pm

Oh, I thought you meant the dynamic allocations. Sorry my bad, I really had to read that twice to see that for some reason. And even then what on earth was I thinking, I must have got lost somewhere.

#98208 - tepples - Mon Aug 14, 2006 1:59 am

lostgame wrote:
Is there any way to see how much of the GBA's RAM and procesor is being used in VisualBoyAdvance?

Yes. Use the tool arm-eabi-nm (called arm-elf-nm on my machine[1]):
Code:
E:\gbadev\tod>arm-elf-nm -n tod.elf

00080000 ? _stack
02000000 A __text_start
02000000 T _start
020000c0 t rom_header_end
020000c4 T __boot_method
020000c5 T __slave_number
020000e0 T start_vector
02000126 t DoEWRAMClear
02000130 t SkipEWRAMClear
[ several lines omitted ]
02007994 r hirescostable
02008198 R _ctype_
0200829c R _global_impure_ptr
0200842c d __CTOR_LIST__
02008430 d __CTOR_END__
02008434 d __DTOR_LIST__
02008438 d __DTOR_END__
0200843c d __JCR_END__
0200843c d __JCR_LIST__
02008440 r __EH_FRAME_BEGIN__
02008440 r __FRAME_END__
02008444 A __iwram_lma
0200873c A __data_lma
02008b8c A __eheap_start
02008b8c A __end__
02008b8c A __ewram_end
02008b8c A __ewram_lma
02008b8c A __ewram_overlay_end
02008b8c A __ewram_overlay_lma
02008b8c A __ewram_overlay_start
02008b8c A __ewram_start
02008b8c A __iwram_overlay_lma
02008b8c A __load_start_ewram0
[overlays omitted]
02008b8c A __load_stop_iwram9
02008b8c A __sbss_end
02008b8c A __sbss_start
02008b8c A _end
[contents of IWRAM omitted]

So it appears you can do something with the _end symbol to see how much RAM your program is using. If you are using appended data, you'll have to take that into account too. I'm not sure if the default link script supports safe interaction between malloc() and appended data frameworks such as GBFS.

[1] I'm still on devkitARM R18 because devkitARM R19 has had known bugs in its handling of memory regions in GBA mode. PM me if those have been definitively resolved.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#98293 - wintermute - Mon Aug 14, 2006 2:43 pm

tepples wrote:



[1] I'm still on devkitARM R18 because devkitARM R19 has had known bugs in its handling of memory regions in GBA mode. PM me if those have been definitively resolved.[/size]


Try and keep up

http://www.devkitpro.org/index.php?action=fullnews&id=116
_________________
devkitPro - professional toolchains at amateur prices
devkitPro IRC support
Personal Blog