Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

DarkBASIC Discussion / Dark Basic Collision Made Simple

Author
Message
TDK
Retired Moderator
21
Years of Service
User Offline
Joined: 19th Nov 2002
Location: UK
Posted: 20th Dec 2006 18:53 Edited at: 29th Oct 2009 16:18
Dark Basic Collision (DBC & DBP)


Very few games can be written without some form of collision. You need a way to stop your character from walking through walls/other characters or dropping through the floor he/she is walking on. This is what the collision commands are for.

In a nutshell, the DB collision commands simpy alert you when certain objects bump into each other. This is in 3D by the way - sprites in 2D also have collision, but sprites are the topic of another tutorial.

Before we start though, I have to explain that you will find a number of third party aids to help with collision - like Sparky's external dll, because it's widely reported that DB's in-built collision commands are neither all that accurate nor particularly fast when put to the test. I've not had cause yet to stretch them that far, so I cannot confirm this from personal experience but have to believe that this is probably true.

However, having said that, I think it's important to get to know how the built-in commands are used. Try them. Once you understand how they work, implementing a third party solution is made that much easier. What's more, you may even find that the DB collision commands are actually more than enough for your needs - without you having to go away and try and learn a new set of commands.

The two basic collision commands in DB are:

OBJECT HIT(ObjNumA, ObjNumB)
OBJECT COLLISION(ObjNumA, ObjNumB)

The first command alerts you if object A bumps into object B, whereas the second lets you know if object A is overlapping object B.

The two parameters ObjNumA and ObjNumB are your main control character's object number (A) and the object you are testing for collision with (B) - both are integers.

Copy and paste the following code in the DB classic editor and run it. Use the cursor keys in this top-down view to run the red cube into the white one.



You will have noticed that when you bump into the white cube, it flashes black. In the code, you can see that the colour of the stationary cube is set when OBJECT HIT(1,2) returns a 1. The Repeat...Until loop immediately after this executes continuously until OBJECT HIT(1,2) returns a 0, at which point the stationary cube is returned back to white.

However when the program is running and you hit the other cube, it turns black then immediately returns to white and you continue passing through the other cube.

Passing through the other cube is what should happen because we haven't yet written any code to handle what happens when a collision does occur, (it's not automatic).

As for the colour flashing, that's because OBJECT HIT does just that - it detects the first contact between two objects. It isn't triggered again while the two objects are colliding - you need to move your cube completely away from the other to end the collision and then bump back into it again to trigger another hit.

So how do we know if a collision is still occuring after the initial hit?

Enter the OBJECT COLLISION command...

This is similar to OBJECT HIT, but returns a 1 if two objects are overlapping. Try running the following program:



It's basically the same as the first example apart from inside the main Do..Loop. But this time, when you bump into the stationary cube, it stays black until you move off it. This is because once the initial 'hit' is recorded, we set a flag (change the value of a variable) to denote that a collision has occured. In this case, we set the variable FirstHit to 1.

When this is set to 1, the code in the If FirstHit=1 block is carried out each time around the loop. Before the initial collision, FirstHit was set to 0 (zero), so it was ignored.

In the If FirstHit=1 block, we test with OBJECT COLLISION. While objects 1 and 2 are overlapping, this will always return a 1. The next line checks to see if it returned 0 and when it does, (only when the objects are not colliding), it returns the other cube back to white and turns the flag back off so the If FirstHit block isn't executed again unneccessarily.

So now, we know how to detect a collision between two objects. But, have you noticed the downside?

Here we are just testing for collisions between objects 1 (our cube) and 2 using OBJECT HIT(1,2) and OBJECT COLLISION(1,2). But what if we have another object - or dozens more objects? Won't we need a line of code for each of them?

Well, no actually, we don't. Remember the ObjNumA and ObjNumB from earlier?

A useful little option is to use a 0 (zero) for ObjNumB, making it HIT(1,0) and COLLISION(1,0). With this option, the command no longer returns a 0 or a 1, but instead returns zero or the number of the object that object 1 (our cube) is colliding with! Now that's a bit more useful don't you think?...

So let's see how to detect collision with many objects when you don't know what object numbers they are...



Important Note: In this example, if two objects are close to each other, then it's possible to still be colliding with one object when you hit another. In such a case, the hit on the second object is not detected. This is because if OBJECT COLLISION() is returning any value other than 0 then OBJECT HIT() is not tested for. It doesn't matter that the object you hit is different to the one you are currently colliding with.

This is normal and won't be a problem when we actually come to handling the collision later.

So we now know how to detect when we hit another object - regardless of object number. Next we have to deal with it because as you have seen, detecting the other object doesn't stop you moving through it.

What method we use depends on the method used to move the object we are controlling. There are two main ways to move a 3D object around:

The first is to turn it in the required direction, then use the Move command to move it the required amount in the direction it is facing.

The second is to use variables for the X, Y and Z position and use Position Object along with the Rotate commands to move the object about.

Our examples so far use the first method. This makes it easy to handle basic object collision because we can simply use the Move command to move back to the very last position before by using a minus value.

Here's the next example...



You will notice first of all that this example does not use OBJECT HIT(). You don't have to if you know that all the objects in your program are simply objects that you cannot pass through. If this is the case - like this program - you just stop your object from passing through any them.

However, if some of your objects are not solid, then you would use OBJECT HIT() to detect the number of the object you just collided with, before deciding how to deal with the collision.

Also, the actual collision effect used here when the cube hits the wall isn't the best for a game. When a game character hits a wall at an angle, the game's continuity and smooth running is interrupted if the character comes to a dead halt. The alternative is 'Sliding Collision' which is no more realistic when you think about it - when was the last time you ran into a brick wall and 'slid' along it - but it does look and feel much better in a game.

The changes to this program from the last one are a little more substantial too.

First of all, we create a wall as object number 2. We also place the camera a little further 'South' of our cube so we can see the wall at a better angle.

We also create a new variable called Speed# with which to move our cube around.

The reason for this is that when a collision is detected, we have to move the cube backwards, away from the wall, but only if we are moving forwards! The cursor down key lets us back away from the wall, but what if we bump into the wall while moving backwards? Well, when the collision is detected we would move the cube backwards further into the wall.

So, to prevent this from happening, we use a variable to store the current direction. When we press cursor up, Speed# is set to a positive number so the cube moves forwards. When we press cursor down, Speed# is set to a negative number so the cube moves backwards.

The advantage of this is that it doesn't matter what direction the cube is heading, moving it 0-Speed# ALWAYS moves it in the opposite direction by the same amount.

So, in the example, in the loop we test to see if a collision has been triggered with:

If OBJECT COLLISION(1,0)>0

If our cube hits anything, the code in this block will be executed. In the event of a collision therefore, we use a Repeat...Until loop moving the cube back with Move Object 1,0-Speed#, which as mentioned previously moves the cube back. As this is in a repeat loop, it's repeated until the cube is no longer in collision with the wall, at which point the loop is exited.

This method isn't perfect because at certain angles, you can clip the wall with the corner of the cube when rotating it - in which case, the backing out routine kicks in and you are instantly 'transported' to the other end of the wall! For this reason, there's a little more work involved, but it's better to use the X, Y and Z variables for moving objects around if you need collision rather than Move.

So let's now take a look at Sliding Collision...

Sliding collision isn't that much different to what we've just been doing.

The basic difference is that we have to use collision boxes. We don't just move back to the last known good position, we use other DB commands to tell us where to go back to.

Collision boxes are invisible 'wrappers' that you apply to objects. These wrappers can give you feedback on collision and you simply size them to fit the object you are applying them to. If you move the object, then the collision box moves with it.

The new command we are going to use is MAKE OBJECT COLLISION BOX Object Number,x1,y1,z1,x2,y2,z2,flag and looks rather complicated with all those parameters. But believe me it's not really. Let's go through them...

Object Number

Obviously this is the number of the object that you are creating the collision box for.

X1,Y1,Z1

OK, remember that I just said that when you move an object, then the collision box moves with it? That's because the collision box is attached to the object number. As an object can be placed anywhere in your world with the Position Object X,Y,Z command, we can't use 'real' X,Y,Z world location co-ords to define the collision box because if we moved the object, the collision box would still be at the old location.

So, instead, when you define a collision box, you use X,Y,Z OFFSETS which assume that the object is at point 0,0,0 in space. This is a neat method as we can use negative and positive values which remain true wherever the object is placed.

OK, an example. Imagine a box or wall 100 wide (X), 50 tall (Y) and 10 Deep (Z). We make the object with Make Object Box 1,100,50,10 and the CENTRE of this box is positioned at 0,0,0 in space.

Therefore, the X offset to reach the left edge of the box along the X axis is -50 and this is used for the value X1. We repeat the process for the Y and Z axis. With a box 50 tall, Y1 is -25 and with a depth of 10 then Z1 is -5.

Notice that the values are the negative equivalent of the boxes X, Y and Z dimensions divided by 2. Eg: Width (X) = 100/2 = 50 which makes -50.

X2,Y2,Z2

If we follow the X axis from the centre 'til we reach the right edge of the box we find that it is at 50, so this is used for the X2 parameter. In the same fashion, Y2 is 25 and Z2 is 5. Notice this time that if X1 = -50 then X2 is 50 and that if Y1 is -25 then Y2 will be 25 and so on.

Here's a small image to show you what exactly is happening:




In the image, our object (the wall) is green. The X, Y and Z world axis are the black lines and where they all intersect, is position 0,0,0. As you can see, this is exactly in the centre of our wall. The dimensions of the wall are shown in blue.

If the X axis is 0 at the centre of the object, the values run negative to the left and positive to the right.

The red distances are those used for the offset parameters. The important thing to realise using this method is that as mentioned earlier, once these offsets are defined, even if the wall was moved to another X,Y,Z location, the offsets would still define the collision box correctly, whereas real X,Y,Z locations would not.

The origin for the offsets is based on the X,Y,Z world position of the Object whose number you supply. Easy eh?

Let's see the code:



When the program is running, in the main loop, we check for the cursor keys and move the cube in the required direction or rotate it and then grab the object's new position into the variables XPos#, YPos# and ZPos#.

We then test for a collision with Object Collision(1,0) and if the result is anything but a zero then we've hit something. The value returned is the number of the object we are banging our head against.

We next use three functions we've not seen before: Get Object Collision X(), Get Object Collision Y() and Get Object Collision Z().

If you cast your mind back to when I was describing how you use the Make Object Collision Box command, I mentioned that the last parameter was called flag and that if you set it to 1 then the collision box rotated with the object. Remember? Well, if you set that flag to zero, you can use the Get Object Collision functions.

These return the sliding collision values which we use to back up our object. Remember though that they ONLY return data if that little flag is set to 0!

So, armed with the amount to back up in the X, Y and Z directions, we decrement them from our object's X, Y and Z positions and use Position Object to place the object in it's new position. The rest of the code simply handles the camera to follow the cube.

Well, that's the end of this tutorial on Simple DB Collision and armed with this new knowledge, you can investigate the many other collision commands DB supplies you with.

There are many more tutorials and example code snippets on TDKMan.com. Click on the link below - it's free to register and everyone's welcome!

Visit TDKMan.com

TDK_Man

TDK
Retired Moderator
21
Years of Service
User Offline
Joined: 19th Nov 2002
Location: UK
Soroki
18
Years of Service
User Offline
Joined: 26th Jan 2006
Location: United States
Posted: 20th Dec 2006 19:45 Edited at: 20th Dec 2006 19:49
Thanks TDK. I guess no one uses DBC very much anymore, but I still use it every day. I am making a game where collision is the biggest element(lots and lots of objects) and your tutorial helps out a a lot. Oh yeah, and HOORAY I REPLIED FIRST! LOL.

TDK
Retired Moderator
21
Years of Service
User Offline
Joined: 19th Nov 2002
Location: UK
Posted: 20th Dec 2006 22:04
This isn't a DB Classic only tutorial - it applies to DBP as well.

And I use DBC every day too...

TDK_Man

RUCCUS
19
Years of Service
User Offline
Joined: 11th Dec 2004
Location: Canada
Posted: 21st Dec 2006 14:34
TDK this is great, Im adding a link to it from the collision resource stickied up top, if you want it removed just say the word.

Kieran
17
Years of Service
User Offline
Joined: 6th Aug 2006
Location: Hamilton, New Zealand
Posted: 30th Dec 2006 11:19
awesome TDK i was stuck on collision for ages! although the sliding collision doesnt work on carefully sculpted .x models so im sticking with the other collision. sadly i managed to manevour (or whatever) through the wall

Kieran
17
Years of Service
User Offline
Joined: 6th Aug 2006
Location: Hamilton, New Zealand
Posted: 30th Dec 2006 11:24
im getting very depressed... it wont fix

TDK
Retired Moderator
21
Years of Service
User Offline
Joined: 19th Nov 2002
Location: UK
Posted: 30th Dec 2006 15:27
The examples in this are only using native DB collision commands and as such are very basic.

The collision detection used is with a bog-standard box, so if you have a non-box shaped object there are going to be parts which the collision box doesn't fit snugly with.

You can always make the collision box a bit bigger in case it's not enclosing the whole object fully - but then there may be parts within the box that you ought to be able to go, but can't.

At the end of the day, this tutorial is meant to show just the basics and hopefully make something like Sparky's dll that bit easier to move on to.

TDK_Man

Kieran
17
Years of Service
User Offline
Joined: 6th Aug 2006
Location: Hamilton, New Zealand
Posted: 31st Dec 2006 00:40
im using sparkys now lol its easier to do collisions with .x models

king jelly fish
17
Years of Service
User Offline
Joined: 26th Feb 2007
Location:
Posted: 1st Mar 2007 05:37
in lhe least gay possibul way ....
i love you

(\__/)
(O.o )
(> < ) This is Bunny. Copy Bunny into your signature to help him on his way to world domination!
Code Dragon
17
Years of Service
User Offline
Joined: 21st Aug 2006
Location: Everywhere
Posted: 17th Mar 2007 17:55 Edited at: 28th Apr 2007 23:27
Thank you so much for writing this up. I never was able to do sliding collision in 3D until today.

These built in commands might actually be all I need, even for a big 3d platformer.

I made this little program to test out the collision physics, and it worked a lot better than I expected. Use arrowkeys to move and space to jump.



I just have one question, how should I make collision on stairs? Even the smallest slope doesn't let the cube slide up instead of back, and I don't want to keep jumping to get to higher places.

[edit]

Nevermind, I just got Sparky's Dll and it's awesome. The commands in it work very similarly to the ones in this tut so learning it was easy.

By reading this sentence you have given me brief control of your mind.
destroy89
17
Years of Service
User Offline
Joined: 27th Jan 2007
Location:
Posted: 21st Jun 2007 20:32
How about collision between vertex modified cubes using the set object collision to polygon option? Can/does dark basic pro handle this properly? Are plugins the only way to get accurate polygon collisions?

See my other post here about this here for a little more detail:

http://forum.thegamecreators.com/?m=forum_view&t=108648&b=1
Insert Name Here
17
Years of Service
User Offline
Joined: 20th Mar 2007
Location: Worcester, England
Posted: 12th Aug 2007 22:50 Edited at: 12th Aug 2007 22:51
What? Game over man, game over? What is the forum talking about?

(N-1)/n*100<n2/n-n/2+n/4*2+100
Gonzaga
16
Years of Service
User Offline
Joined: 15th Aug 2007
Location:
Posted: 21st Aug 2007 22:28 Edited at: 22nd Aug 2007 07:30
Can you use Sparky's dll in DBC? I thought it was only for DBPro? I downloaded - the read me file only instances placement for the dll in a file not present in DBC. I must have placed it wrong, because running the demos I get a syntax error. Yes, I have upgraded my DBC to 1.13...any help?
Sixty Squares
17
Years of Service
User Offline
Joined: 7th Jun 2006
Location: Somewhere in the world
Posted: 24th Aug 2007 04:54
Great tutorial, but I noticed one thing. In that last example with the sliding collision you wrote "POS#" in your "set camera to follow" command instead of "XPOS#" Yes I know it doesn't really matter lol.

TDK
Retired Moderator
21
Years of Service
User Offline
Joined: 19th Nov 2002
Location: UK
Posted: 24th Aug 2007 08:38
Well done spotting that - and thanks for letting me know.

Fixed!

TDK_Man

Gonzaga
16
Years of Service
User Offline
Joined: 15th Aug 2007
Location:
Posted: 27th Sep 2007 06:33
So, going back to the sliding code snippet - which is just what I was looking for - how would you go about doing this with a .x object you've loaded? I loaded a test building with walls, but so far, the only way I've been able to stop my character from going through the walls is to set object collision to boxes with my character...or would I just need to do the very time-consuming thing and create collision boxes around all my walls?
Yodaman Jer
User Banned
Posted: 27th Dec 2007 21:12
I have one little problem.
I can't get the "SET OBJECT COLLISION TO POLYGONS [OBJECT#]" command to work at all.
Is there something I have to do, like make a whole new area of code after the sliding collision is programmed?
Maybe something like:

That's for sliding collision (as you know). I thought maybe if I used it in conjunction with the sliding collision it would work. I was wrong.
Can you point me in the direction of a tut that explains the POLYGONS commands throughly and easily please?
Thanks is advance,

Yodaman Jer

Wii came . . . Wii saw . . . Wii conquered!
DB newbie
18
Years of Service
User Offline
Joined: 13th Nov 2005
Location: um..... i dont remember.
Posted: 5th Jan 2008 20:28
yes awsome job TDK for me collision was one of the hardest things and now i finally got it...woot woot kudos to you.


Come see the WIP!

Login to post a reply

Server time is: 2024-04-24 05:45:07
Your offset time is: 2024-04-24 05:45:07