Level: Intermediate/Advanced
Hello again everyone. Welcome to my new tutorial. This one will be covering something called
Handles. Handles are basically a way to 'handle' (suprise suprise) aspects of your program while still keeping control. They make strong use of variables, parameters, types, and advanced arrays, and when used properly, you can build a game engine that can easily flourish into a full feature rich game.
Before we begin, lets look at some DBP examples, to understand what handles are and why they would be usefull.
Let's make a simple cube:
Now, to control that cube, you have to remember that it is object number 1. Infact, if you use this system, you are going to have a whole load of remembering to do. Not only that, but when you assign a number to every object in your game, it will be too stiff and unexpandable. I mean, imagine you have all your game set out just perfect, but then you notice you want to add an extra particle emitter here or a new barrel there? Your game will start falling apart from that very moment - and usually, that moment comes pretty early on in the development process.
This is where handles can start coming in to play. Using them, you dont have to worry about object numbers.
MyCube = 1
Make Object Cube MyCube, 100
To control this cube, you just have to use MyCube. When you want to change that object number, you just change the MyCube variable. OK, this is certainly better than the previous example, because you can always scramble up the order of the objects and you dont have to worry about the rest of your code, but the thing with good handling is that you dont have to worry about the nitty-gritty stuff that lies underneath your engine.
The most common solution in this case is to make a FreeObject() function. It has been made many times, in many different ways. It is extremelly useful, because all you have to worry about is the variable, and the object orders will wort themselfs out. There is no need to worry using the same object twice. FreeObject() functions just use a simple search technique, which is this case is good, but for other handlers, it can get better.
Here is a very, very basic FreeObject() function.
Function FreeObject()
` Loop until an object does not exist
Repeat
Inc I
Until Object Exist(I) = 0
EndFunction I
Great, now you can do this:
MyCube = FreeObject()
Make Object Cube MyCube, 100
Or could even be used further for this:
Now that is really awesome... for object handling. You can create objects without worrying about numbers. It's really good!
Now, ask yourself this, what if you wanted to do this?:
Dim Cubes(5)
Cubes(1) = FreeObject()
Cubes(2) = FreeObject()
Cubes(3) = FreeObject()
Cubes(4) = FreeObject()
Cubes(5) = FreeObject()
That wouldn't work! Cubes(1) - Cubes(5) would all be exactly the same value because an object wasn't created after each FreeObject() call, therefore it will always return the same number.
This is where you have to know some more advanced array/linked-list techniques. This is how it works. You create a boolean array with no elements. When you call FreeObject(), you increase the size of that array by 1. Get the size of the array, and check if an object which has the number of the size of the array exists. If it doesn't, and the current array item isn't set to 1, then, set it to 1. This will essentially "reserve" the object, so next time, it will move up an array item, and not worry about overwriting the previous one.
Here's how to do it:
` Object array
Global Dim _ObjTaken(0) as Boolean
` Free Object
Function FreeObject( )
` Add to array
Array Insert At Bottom _ObjTaken()
Obj = Array Count( _ObjTaken() )
` If object Obj doesnt exist, and isnt reserved..
If ( (Object Exist( Obj ) = 0) && (_ObjTaken(Obj) = 0) )
` Reserve
_ObjTaken( Obj ) = 1
` Return object
ExitFunction Obj
Endif
EndFunction 0
Now, this example will work perfectly!
Dim Cubes(5)
Cubes(1) = FreeObject()
Cubes(2) = FreeObject()
Cubes(3) = FreeObject()
Cubes(4) = FreeObject()
Cubes(5) = FreeObject()
(Note: This will only work is you did not use any other method previously of creating objects)
OK, so we have objects sorted (and ofcourse you can use this for images, sprites, etc). But just because objects are single entities doesn't mean they are the only thing that can have handles!
So let's take it a step further. What happens when you want groups of objects? Would you want to go about giving a handle to every object? I shouldn't think so. (Dont get me wrong, FreeObject() will still be used in this)
Lets say you want to make groups of objects, and each group covered a range of objects. The group itself would have the handle. The details of it is quite simple. A zero array for groups, and a type for the group, which will have two fields: a pointer to the first object it covers, and a pointer to the last one.
So, maybe something like this:
` Group data
Type tGroup
StartObj as Integer
EndObj as Integer
EndType
` Group array
Global Dim _Group(0) as tGroup
` Create group
Function CreateGroup( StartObj, EndObj )
` Create new group
Array Insert At Bottom _Group()
Grp = Array Count( _Group() )
` Set group objects
_Group( Grp ).StartObj = StartObj
_Group( Grp ).EndObj = EndObj
EndFunction Grp
Now you can create a group of objects. MyGroup = CreateGroup( 1, 100 ). Simple. It may not seem very useful yet, but, say you wanted to hae a group of objects say, representing vehicles. You might have an array of vehicles, each with an object number, and, if they were created sequentially, they would be numbered sequentially (assuming you were using that FreeObject() function). You can use this group to perform a function such as delete.
` Make a group of all 10 vehicles
Vehicles = CreateGroup( Vehicle(1).Obj, Vehicle(10).Obj )
...
` Delete them
DeleteGroup( Vehicles )
` Delete a group
Function DeleteGroup( Grp )
` Loop through group's objects
For o = _Group( Grp ).StartObj to _Group( Grp ).EndObj
` Delete objects
Delete Object o
Next o
EndFunction
This is where things properly start getting useful. You will notice that when I call the DeleteGroup() function, I pass a handle to the group, that is, the integer 'Vehicles'. Think about it, a whole group of objects.. stored in a single integer. If you are like me, you will find this amazing, because when you compress huge complex structures into something as simple as an integer, you have alot more power, control, and strength in your engine, than if you did trying to do everything manually.
Now, lets move out a little more. Forget about objects. You can have a handle for anything. Lets make a handle for people data.
` Person's data
Type tPerson
Name as String
Age as Integer
Height as Float
ShoeSize as Integer
Endtype
` People
Global Dim _Person(0) as tPerson
` Create me
Me = CreatePerson( "Alastair Zotos", 16, 5.7, 10 )
` Kill me :(
KillPerson( Me )
` Create a person
Function CreatePerson( Name as String, Age as Integer, Height as Float, ShoeSize as Integer )
` Create new person
Array Insert At Bottom _Person()
Person = Array Count( _Person() )
` Set data
_Person(Person).Name = Name
_Person(Person).Age = Age
_Person(Person).Height = Height
_Person(Person).ShoeSize = ShoeSize
Endfunction Person
` Kill Person
Function KillPerson( Person )
` Delete
Array Delete Element _Person(), Person
Endfunction
Very basic example, but it's there to prove that you dont need objects to work with them. You can have a handle for simple data.
The reason I used people in this example, is because you can easily build on it. When I was making my Lunar Lander game (which worked with planets rather than flat landscapes) the worlds were built as such: Tiles -> Landscapes -> Worlds. Each world had a certain amount of landscapes, and each landscape has a certain about of tiles, and each tile had some associated data. All had handles. In the same way, you can use people, i.e. people -> town -> country -> planet. This is, where you have handles for people, but you can also have a handle for a town which has people in it, and so on.
I will only go up one level in this (assume I have the previous people code in here still):
` Town data
Type tTown
Name as String
StartPerson as Integer
EndPerson as Integer
EndType
` Towns
Global Dim _Town(0) as tTown
` Create town
MyTown = CreateTown( "Glasgow", 1, 100 )
` Destory my town (about bloody time)
DestoryTown( MyTown )
` Create a town
Function CreateTown( Name as String, StartPerson, EndPerson )
` Create new town
Array Insert At Bottom _Town()
Town = Array Count( _Town() )
` Set town's people
_Town( Town ).Name = Name
_Town( Town ).StartPerson = StartPerson
_Town( Town ).EndPerson = EndPerson
EndFunction Town
` Destory a town and all it's inhabitants
Function DestroyTown( Town )
` Kill inhabitants
For p = _Town( Town ).StartPerson to _Town( Town ).EndPerson
KillPerson( p )
Next p
` Delete Town
Array Delete Element _Town(), Town
EndFunction
This can be further created to incorporate whole countries, then planets, even solar systems! Of course, none of it is visible, but that's not the point. The point is, that if you did infact want to make a game such as this, you would have to have some way of
handling all your people. So if you did infact go as far as slar systems, you could infact number every person's object number, but I wouldn't recommend that. You could use an array for each person and use FreeObject(), but I wouldn't recommend that either. You could use this method, where you have control over whole solar systems, just by having access to a single little integer.
I hope you have understood this tutorial, and found it useful, because I dont have the brain capacity to explain how much I have. It is a very useful way of doing things, and all it requires is a little knowledge about types, and some slightly advanced array commands, but, not that advanced
Cheers
C&C Please
"It's like floating a boat on a liquid that I don't know, but I'm quite happy to drink it if I'm thirsty enough" - Me being a good programmer but sucking at computers