= Pickups =
== Description ==
Pickups, or more precisely Pickupables (in the following referred to as pickups), are items that can be picked up by other entities (which are derived from the PickupCarrier class and I will in the following simply refer to as carriers) and have some effect on the carrier.
== HowTo's ==
I want to start with explaining, how pickups can be included in levels and how new pickups can be created (coded).
=== Including pickups in a level ===
I wanted to make including pickups in level as simple as possible, while also ensuring a division between the pickup itself and how it looks. For you to be able to use pickups in your level you need to understand a few concepts.
* Pickups (Pickupables) are entities which have no physical (or graphical) dimension. The simply represent the effect they will have on a carrier, when used.
* The physical (or graphical) dimension of a pickup is called a PickupRepresentation (or in the following referred to as representation).
* The representation of a pickup and the pickup itself are linked to each other, meaning a representation can only represent one type of pickup.
* The entity that actually gives a pickup to a carrier is called a PickupSpawner (in the following called spawner). A spawner creates (based on some parameters) pickups which can be picked up and how the spawner looks in the game is defined by the representation of the pickup it spawns.
* A type of pickup is a specific pickup class with values for all its relevant parameters. This means, that a pickup of the same class with the same values for all parameters except for one is a different type of pickup and will therefore have a different representation.
==== Using predefined pickups ====
There is a file called pickup_representation_templates.oxt, which holds the templates for the representations and also templates for pickups. If you want to use pickups you will have to include this file in your level file, somewhere above the Level-tag.
{{{
}}}
There is another file called pickups.oxi which creates all representations needed for the pickups supplied by the pickup_representation_templates.oxt file. You will have to include it as well. It has to be some where after the opening Scene-tag and your first use of a pickup.
{{{
}}}
After that you can use all the predefined pickups specified in those two files just by creating a spawner for them in your level. e.g.
{{{
}}}
Or even simpler, you can use the templates for pickups specified in the pickup_representation_templates.oxt file, e.g.
{{{
}}}
==== Using non-predefined pickups ====
Now let's assume you're not satisfied with the pickups that are provided by the two before mentioned file, but you're not much of a coder as well. Luckily there is a way for you. Pickups were created with a broad range of use in mind, which means that the pickups provided by the files are not all there is.
There is no minimum requirement to use pickups in your level files, as long as they have been coded in C++. e.g.
{{{
}}}
As you can see in the pickup_representation_templates.oxt file and the pickups.oxi file there is no representation defined for this pickup, so the default representation will be used.
Now let us assume you want to create a representation for the inserted pickup above. This is done by creating a representation within the scene.
{{{
}}}
As you maybe have noticed by now, we also have to define the template for the representation which is used in
{{{
spawnerTemplate = "newhealthpickupRepresentation"
}}}
the template you need to create defines how the pickup (or actually the spawner) is displayed in your level.
{{{
-- Here you can put all the objects which define the look of the spawner. --
}}}
Your done. Now you have a new pickup type with an appropriate representation for your use. If you feel that it is useful in general please don't hesitate create a template for the pickup and add your pickup to the pickup_representation_templates.oxt file and the pickups.oxi file, so that anyone who wants to use kit can do so quite easily.
Let's assume you're still not satisfied. I mean, come on, we just used a pickup that already existed and created a new type by changing some parameter values and adding a representation, that's not really anything new now, is it?
Well I've got something for you. It's called a PickupCollection (in the following just referred to as collection). A collection is comprised of many different types of pickups and behaves just as if it were one pickup itself. This is how you create one:
{{{
-- some pickups you want th have in your collection, e.g. --
}}}
That's it, there's nothing more to it. However if you have questions regarding any of the above please feel free to contact [wiki:DamianFrick me].
=== Creating a new pickup ===
Now it get's a little trickier. Therefore I'm just going to supply you with a recipe, or a set of steps you have to take, without which your pickup won't work.
==== Creating the class ====
For a new pickup you need to create a new class in modules/pickup/items. Your class needs to be derived from another pickup class, normally this would either be Pickupable or Pickup. Pickupable is (as mentioned earlier) the base class of all things that can be picked up, thus of all pickups. However you are brobably going to want to derive your class form Pickup, because it provides some useful methods. So have a look at Pickup.
Once you have created your new pickup class you have to insert it in the PickupPrereqs.h file in the modules/pickup folder and in the CMakeList.txt file in the modules/pickup/items folder. Also have a look at other pickups to make sure you include all the necessary files in your class.
Additionally you have to add your pickup as a friend of the PickupCarrier class. To that purpose open PickupCarrier.h in the orxonox/interfaces folder and add your class under
{{{
//! Pre-declarations.
}}}
and under
{{{
//! Friends.
}}}
==== Coosing the carriers ====
You also have to choose the carriers that are allowed to pick your pickup up. After you have chosen the entity that carries your pickup you need to do the following.
* The enity that carries your pickup needs to be derived from the PickupCarrier interface. And you need to implement the PickupCarriers virtual functions getCarrierChildren() and getCarrierParent(). Now let me explain, very briefly, why these functions are needed. All pickups are initially picked up by a pawn and the "propagated", or handed down to the entity that carries them. With the above mentioned two function just that is done. A hierarchical structure is established with one parent and a set of children, where the Pawn is the root node of this hierarchical structure, the only entity with no parent.
* Once you have done that you will also want to specify in your pickup by which carriers it can be picked up, this is done via the addTarget() function. So you have to make sure the target is added whenever one of your pickups is created (so, most conveniently somewhere in the constructor), with the following command.
{{{
this->addTarget(ClassIdentifier::getIdentifier());
}}}
==== Creating the inner workings of your pickup ====
Now that we have the skeleton of a pickup and we have defined which carriers are allowed to pick our pickup up we are going to take a look at all the methods we can (or sometimes have to) overload from Pickupable, for our pickup to work properly. Bu firstly I will introduce some more concepts to make the need for these methods more obvious.
* Since one pickup class can itself be many pickup types we need a way to find out whether a particular instance of a pickup is of the same type as another instance of a pickup. To that end the PickupIdentifier (in the following just called identifier) was created. The PickupIdentifier accounts for the type of class your pickup is of and also for the parameters (and their values) that distinguish different types of pickups of the same class. Much of the functionality of the pickup module relies on this identifier being correct, thus it is very important to initialize it correctly. (We will see, how that is done in a short while.)
* Every pickup has at least two states which are very important. The first is, whether the pickup is currently in use or not and the second is whether the pickup is currently picked up or not.
Now lets look at the important methods.
* changedUsed() The changedUsed() method is called whenever the state of the pickup transits from being used to not being used or the other way around. Which means this method is probably the most important method you have at your fingertips, since it enables you to apply the effect of your pickup when it gets used and remove the effect as soon as it is no longer in use.
* changedPickedUp() The changedPickedUp() method is called whenever the state of the pickup changes from being picked up to not being picked up or the other way around. For example if you want your pickup to be used as soon as it is picked up, this is the method you have to overload to achieve that behavior (or just let your pickup be derived from Pickup, which implements exactly that behavior if the activationType is set to 'immediate'). You don't have to concern yourself with destroying the pickup or creating a spawner when it changes to not picked up, since that is already implemented with the Pickupable and PickupCarrier class. If you want a different behavior, however once again, this is the method.
* changedCarrier() The changedCarrier() method is called whenever the carrier of the pickup changes. And by that I don't mean the class that is allowed to carry the pickup, but the object that actually carries (or carried) the pickup. Please do not overload this class to implement behavior for picked up -> not picked up transitions, use changedPickedUp() for that. For most pickup classes this method doesn't need to be overloaded, one use for it, however is in the PickupCollection class, where the new carrier needed to be communicated to all pickups the collection consists of, whenever the carrier was changed.
Please be aware, that these three methods are methods registered with Super, meaning, that whenever overloading them, don't forget to call SUPER(MyClass, myMethod);
* a
=== Making your object pickupable ===