Part 4:
Items And Enemies
Back to the overview

In this tutorial we’ll import a couple of items that the player can pick up. We’ll also import an enemy character and his animations. This enemy needs to have his own primitive AI behavior. Next, we’ll elaborate on the object copying we did with the bullets. Instead of creating all items on one spot we’ll read out an array we’ve created to place items. The item collision detection and processing is handled in one global script, whereas the enemies all have their own scripts for object collision detection, proximity testing etcetera. It’s also necessary to implement a system that keeps track of the player’s health (so that the enemies can shoot back).

First we’ll import the items and we’ll create a script that manages the creation (Object Copy BB) and deployment (using an array and a little temporary script). This way we won’t have to write down where we want the items to appear. Next, we’ll use the Get Nearest In Group BB to detect if the player picks up the items and we will create a script that lets us spawn items where we need them. If all that works, the enemy character is next. When we’ve imported the enemy we’ll setup all the necessary attributes (Fixed/Moving obstacle, health attributes) and we’ll start on the enemy AI behavior. This behavior will include basic behavior (i.e. Object Slider, Unlimited Controller BB etc.) and some specific behavior. This includes the orientation (the enemy should look at the player), the movement (he will always try to stay in firing range, the firing (I guess we need some more bullets!) and a death behavior (to make the enemy die and deactivate properly). To wrap things up we need to create a new Level Script, “score”, to keep track of all collected items, health attributes etcetera using Switch On Message BBs and Threshold BBs.

In this fourth part you will have learned how to create more complex behavior scripts. You will also have an idea how to manage data using arrays. The game is looking more alive, now that we have added more dynamic objects to the level. The only thing to do now is to turn this nice collection of scripts into a finished game!

You can continue with your own project or open tutorial_part_4_start.CMO.

time Estimated time to complete:
- 6 hours
zip

Source material included
(Virtools):
- 2 item 3D sprites
- enemy character (including animations, muzzleflash and sounds).
- effect 3D frames
- additional material (textures, sounds etc.)
- start, halfway and final .CMO

pdf PDF file

1 Importing The Items Start off by dragging items.NMO from the 3D Entities Resources into your composition. This file contains two 3D Sprites, their materials, textures and two sound effects (for when you pick them up).

• When you’ve looked at the items in the viewport, go to the Level Manager, select them and hide the two 3D Sprites by clicking on the eye icon. Set initial conditions on the two (by using the right-click menu).

• Now we are going to create two groups. These groups will hold the multiple instances of the items (after we’ve created them). Select the item_health and press “G” to create a new group, call it “item_health_group”. Do the same for the item_ammo. Set initial conditions on both groups.

• Create an empty group (select the Groups folder in the Level Manager and press “G”). Name it “items_activated_group” and set its IC.

Tip: Although it’s not always the most convenient way for viewing, try to locate all important objects always on (0,0,0) or another predetermined point. This way you can easily find them and you won’t have any objects floating around in your scene.

2 The Items Script Create a new Level Script called “items”. Before we script anything, let’s create some local parameters (Alt+”L”) to make life a little easier later on: one for both items (3D Sprites), both groups (Groups), the items_activated_group, one for the maximum amount of each item you want (let’s call it “items_max” and set the type to integer and the value to 10) and a new local character parameter (once again the dummy_character!). Alternatively you could look up a shortcut to the dummy_character elsewhere and create another shortcut in this script.

• Create one Counter BB and two Object Copy BBs. For the Counter BB, use a shortcut to items_max as the count. Set shortcuts to the items as the originals for the Object Copy BBs.
Edit the first Object Copy BB to change the Dependency Options to “Custom Dependencies”. In the Behaviorial Object category, be sure to check Groups Belonging and in the 3D Sprite category uncheck Material (one material is enough!). Why not use this Dependency Options parameter for the other Object Copy BB as well? Connect it to the other one, deleting the linked parameter. Your script feels more optimized already!

• Create a nice BG around the first three BBs of your script and call it “items _copy”. Create a bOut for the BG (don’t forget to connect the Counter BBs bOut to the bOut of the BG!).

3 Creating An Array Now, there are two things we want to do with all these objects we create: 1. Position them on locations we specify ourselves (scattered around the environment). 2. Position them on the location of an enemy when he dies. Let’s start with the first one.

• We are going to use an array to hold all locations where we want the items to appear. Create an array by pressing the array icon in the Level Manager, or by pressing “R”. Name the array (using F2) “items_array”. In the array setup, press Add Column. In the dialog box that appears, Name the column “item_group”, set the Type to “Parameter”, and the Parameter to “Group”. Add another column (“item_location”, Parameter, Vector). Hit Ok. We’re done here, because we are going to create the data inside this array dynamically.

• In the items script, create a new local array parameter to the top of your script (specifying our newly created array). Now add:
Two Key Event BBs (specify the “I” and the “O” key);
A Parameter Selector BB (set the pOut type to “Group” and specify shortcuts to item_health_group and item_ammo_group as the pIns); an Add Row BB (specify a shortcut to the items_array parameter as the array. Edit the BB and press Ok to make the Group and the Vector pIn appear.

• Connect the pOut of the Parameter Selector BB to the first pIn of the Add Row BB. For the second pIn, use a paramOp to get the position of a shortcut to the dummy_character parameter.
Connect the BBs and create a BG around it (“add item to array”). Connect it to Start.


4 Positioning The Items Now we can start placing our items. Run your composition. Navigate through the environment and when you find a good place for an item, you can press I for a health_item and O for an ammo_item. These won’t appear right away, but the type and the location will be stored in the array we created in the last step. When you are done, stop the composition and see if data has been added to your array (you can delete data by selecting rows and pressing delete if you’re not satisfied). Now we must see to it that the objects we’ve copied are placed on these locations when we start our game.

• We are going to use the data we find in each row of the array (a group and a vector) to position an item on a location.
Start off with an Iterator BB (specify the items_array, pOuts will be created after you’ve edited it). Create two new local parameters for the pOuts, one for the group (current_group) and one for the vector (current_vector). Connect its loop out to a new
Identity BB (set its type to 3D Sprite), combined with a paramOp (Get Element). The paramOp gets element “0” from the current_group you’ve just got. Use the Identity BB to put it into a new local 3D Sprite parameter (call it “current_item”) that you must create underneath the Identity BBs pOut.

• Remove the current_item for the current_group, so it won’t be picked again (using a Remove From Group BB). Add the current_item to items_activated_group (using a Add To Group BB). Set the current_item on current_vector (using a Set Postion BB). Show the current_item (using a Show BB) (remember that you’ve made the original items invisible?).

• Now loop the Show BB back to the loop in bIn of the Iterator BB so it will do this for all rows. Create a BG around it called “items_position”. Don’t forget to connect the Iterator BBs bIn to the bIn of the BG and the Iterator BBs bOut to the BGs bOut! If you haven’t done so already, connect the items_copy BG to Start and its bOut to the bIn of the items_position BG. Now, when you run your composition you can see the items you’ve placed!

Note: you can disconnect the “add item to array” BG when you are happy with the locations of the items.

5 Give Items Although we don’t have any enemies yet, we are already going to make the script that places items on their location where they die. Better yet: on whatever location you want!

• Create a Wait Message BB (“give_item” is the message). Add a Get Message Data BB behind it and insert the same message into this BB. Construct a vector output parameter for the BB (using the rightclick-menu) and add a local vector parameter “give_item_position” underneath this new pOut (and connect it to the pOut of course).

• Add a Random Switch BB and a Parameter Selector BB behind the Get Message Data BB. We’ll use the Random Switch BB to choose which item we want. Select the BB and press “O” to add another bOut. Now edit the parameters (specify 0.25, 0.25 and 0.5 as the Coefs). Connect the top two bOut to the bIns of the Parameter Selector BB. Just loop the third one back to the Wait Message BB (so it won’ do anything). This way there’s always half a chance that you won’t get any item at all! Change the pOut type of the Parameter Selector BB to Group. Edit the parameters of the BB (“item_health_group” and “item_ammo_group”). Create a local group parameter underneath the BBs pOut called “selected_item_group”.

• Now we’ve determined what kind of item we want we need to get the specific item from its group and position it. Insert an Identity BB and set its pIn type to 3D Sprite. Create a paramOp (Get Element) above the Identity BB. Enter the “selected_item_group” as the left pIn and a new integer parameter with the value “0” as the right (so we will pick the first item in the group). Underneath the Identity BB, create a new local 3D Sprite parameter called “selected_item”.

• Now add the following BBs, setting the selected_item as the Target Parameter each time: Remove From Group BB (specify selected_item_group as the group), Add To Group BB (specify items_activated_group as the group), Set Position BB (specify give_item_position as the position) and finally a Show BB. Loop the Show BBs bOut back to the Wait Message BBs bIn. Drag a BG around the whole lot and name it “give_item”. Connect its bIn to the bOut of the “items_copy” BG as well. We can’t test this just yet unforntunately.

6 Picking Up Items It won’t be difficult to test if the player picks up an item. We simply need to know if the player is close enough to the nearest item! Then we can hide that particular item, remove it from the items_activated_group and put it back in the group it came from. The last thing we need to do is to send a message that this item has been picked up (we’ll create a script that uses this message later on in this tutorial). The trick is to find out what kind of item you’ve picked up!

• Behind the “items_copy” and the “items_position” BG we are going to insert a Get Nearest In Group BB. Create a new local 3D Sprite parameter underneath its first pOut called “nearest_item”. Loop this BB. Add a Test BB (Less or equal) and connect the Distance pOut of the Get Nearest In Group BB into the A pIn of the Test BB. Set the B pIn to 0.5.

• If the item is closer than 0.5 meters then:
1. Hide it (you might need to add a Target parameter by pressing “T” while the BB is selected).
2. Remove it from the items_activated_group (using a Remove From Group BB).
3. Add it to the right item group (using a Add To Group BB). This is where a couple of paramOps come in handy: first use a Get Name paramOp on the nearest_item. This outputs a string ( i.e. “item_health”). Add to this string another string with the value “_group”, using a paramOp (Addition). This outputs another string (so “item_health” + “_group” makes “item_health_group”). Now use the Get Object By Name paramOp to convert this string into a real Group. Connect this Group to the pIn of the Add To Group BB.
4. Connect the pOut of the Get Name paramOp to the Message pIn of a new Send Message BB. This automatically converts this string into a message. Specify “Level” as the Destination of the message.

• If you’ve done this correctly you can create a BG around this part, call it “items_collection”. You connect its bIn to the bOut of the previous BG (items_position). You’re now able to pick up items! Great! It doesn’t do anything yet though…

7 Attributes Now we’ve set up the biggest part of our item management, it would be nice if we had some variables that actually kept track of things as health and ammo. To do this we are going to create attributes (“parameters” attached to specific objects). This way we don’t have to create a lot of local parameters to keep track of all the enemies’ health. You just have a health attribute with a specific value. When we need to do something with this value (i.e. the enemy is hit) we use the Has Attribute BB and the Set Attribute BB to do this. However, before we can assign attributes, we must first create them.

• Choose Editors > Attributes Manager from the menu to open the Attribute Manager. In the Manager, click Create Attribute to open a dialog window. First we will create a category (a folder) for all attributes specific to our game. Type “Object Properties” in the Create New Category text-field and click Create.

• In the Create New Attribute Type Name text-field, type “character_health”, select “float” as the Parameter Type and select “Object Properties” as the Category. Click Create.
Repeat this for a “character_ammo” attribute and a “object_health” attribute (we’re going to need it if we want to blow stuff up).

• Now we must assign the character attributes to our characters main body part “The Hammer”. Select it in the Level Manager (be sure you have selected the bodypart and not the character!). Use the rightclick menu to select Add Attributes. In the Add Attributes window, select the two character attributes and click Add Selected. The character_health attribute must be set to “1000” and the character_ammo attribute to “100”. You can do this in the Attribute Manager or via the setup of the bodypart. It’s important that you set IC on this bodypart AND the character afterwards, or else you will find that your attributes will be gone!

Tip: When you select attributes in the Attributes Manager, you can view the objects that have that particular attribute in the right part of the screen. You can easily access this objects setup via the rightclick-menu.


8 Keeping Score OK, so we’ve got these attributes on our character bodypart. Now we are going to create a new Level Script “score” to process everything that has to do with these global parameters. We are going to get an attribute, perform a calculation and put it back on the bodypart.

• First off we’re going to add some local parameters that are important to this script: one for the TheHammer (bodypart), one called “health_up_value” (float, value “25”) and one called “ammo_up_value” (float, value “50”).

• To pick up the messages we are sending when we pick up items, we need a Switch On Message BB (“item_health” and “item_ammo” as the messages). Insert a Has Attribute BB (with a shortcut to TheHammer bodypart as the Target. Edit the BB and specify the character_health attribute. A pOut will appear. Add a Threshold BB. Rename the X of the Threshold BB pIn to “health_temp”. Set the Max pIn to “1000”. Add a Set Attribute BB (add the same Target and the same attribute of course), a pIn will appear. Now connect the “health_temp” parameter to : the pOut of the Has Attribute, the pOut of the Threshold BB and the Value pIn of the Set Attribute BB (or you could use shortcuts).

• To add the health_up_value before the attribute value gets set back in the bodypart, we need a paramOp (Addition). Insert it between the health_temp parameter and the pIn of the Threshold BB. We also need a sound effect. Add a Play Sound Instance BB behind the Set Attribute BB. Specify the “item_health” sound and set the Object parameter to “dummy_character”. Connect all BBs in a linear way (as shown in the screenshot).

• Repeat this last process for the item_ammo message. Create a BG called “item_score” and connect it all to Start. When you are testing your script, you can see the attributes values changing in the Attributes Manager. You might want to make the attributes default values somewhat lower or else you can’t see the change! (Don’t forget to set ICs on the bodypart and the character!).

Tip: Keeping the Attributes Manager open while playing your composition can decrease performance.

We have saved our progress up to now as tutorial_part_4_halfway.CMO. You can always check this file if you are really stuck!

9 Importing The Enemy Drag the Enemy1.NMO character from your resources into the composition. Take a look at it in the viewport and in the Level Manager. Notice that “Activate At Scene Start” has already been disabled. Hide the character by clicking the eye icon. We need to import some other things as well: in the Animations folder of your resources, select all Enemy1 animations and drag them onto your character (in the Level Manager). From the 3D Entities folder, drag Enemy1_muzzleflash.NMO into your composition. Look it up in the Level Manager and hide it as well.

• This last object needs to be linked to our Enemy1 character. To do this, first choose Editors > Hierarchy Manager from the menu. Look up the Enemy1 character. To link the Enemy1 Muzzleflash, we first have to dive deeper into the hierarchy of the character to find the Enemy1 R Hand object. Drag the Enemy1 Muzzleflash onto that object.

• Now we have to define the relative position of the muzzeflash. In the setup of the Enemy1 Muzzleflash enter (0.4, 0, 0) as the local position.

• Add a Simple Shadow BB to the Enemy1 bodypart by dragging the BB from the Building Blocks onto the object in the Level Manager (or you could create a script manually). Specify hammer_shadow as the texture.

• Now that we’re so busy setting up the Enemy1, let’s add a character_health attribute to its bodypart as well. Don’t forget to set its value to “100”. Back in the Hierarchy Manager, select the Enemy1 character and use the right-click menu to Set Initial Conditions on Hierarchy.

• The last thing we need to import is a nice sound for the enemy gun. Drag Enemy1_glock.MP3 from the Sound resources into your composition. In its setup, uncheck Streamed and check Point. Set the Min and Max perception distances to 3 and 50.

Tip: Sometimes it is not necessary to give each character a Simple Shadow BB. A plane with a transparent texture at the location of the feet can suffice in some situations.

10 Enemies The AI system we are going to create consists of three parts:
• A Level Script called “enemies” to handle the copying of the enemies and to hold all important parameters concerning the AI (for easy adjustment).
• The AI script itself that defines the behavior of our enemies.
• A script that deploys/spawns enemies where we want them (in our case the Van vehicles, which we’ll handle in the next tutorial).

• Although it might not seem logical, we’ll start of by scripting the Level Script (primarily so we can use shortcuts to parameters later on in our AI script). So, create a new Level Script called “enemies”. We also need a group to hold our copied enemies. Select the Enemy1 character and press “G” to create a new group called “enemy1_group”, containing the Enemy1 character. Also create a group called “characters_activated_group” containing the dummy_character and the “Enemy1” character. Set ICs on both groups.

• In our enemies script, we need quite some new local parameters. They’re written down in this format “Name”, Type, Value. Here we go:
“Enemy1 Character”, Character, Enemy 1
“Enemy1 Group”, Group, enemy1_group
“Shootable Group”, Group, shootable_group
“Characters Activated Group”, Group, characters_activated_group

“Enemy1_approach_distance”, Vector2D, (7, 12)
“Enemy1_fire_distance”, Float, 30
“Enemy1_speed”, Vector, (0, 0, -3) (that’s minus 3)
“Enemy1_orientation_speed”, Percentage, 5%
“Enemy1_maximum”, Integer, 10
“Enemy1_unused”, Integer, 0

“Spawner_maximum”, Float, 25
“Spawner_interval”, Time, 2 seconds
“Spawner_distance” Float, 150

• The only thing left to do now is to create a copy behavior much like we did for the items. Add a Counter BB (use a shortcut to the Enemy1_maximum as the Count pIn) and an Object Copy BB (use Enemy1 Character as the original). In the Dependency Options, be sure to check Basic Object > Unique Name, 3D Entity > Meshes and Behavioral Object > Groups Belonging.
You can create a BG around these BBs called “enemies_copy”.

11 AI For Dummies Before we can create any kind of AI, we need to know what we want our enemies to do. We’ve split the behavior in a couple of chunks:
• Basic behavior: some startup behavior, Objectslider BB, Unlimited Controller BB etc.
• Orientation: we want our enemies to face the player with their bodies and we want them to look at the player as well.
•Translation: the enemies should run towards the player when he’s too far away.
• Avoid: our enemy should avoid other enemies (somehow characters with simple AI always want to be at the same place!)
• Fire: the enemy should be able to fire bullets at the player.
• Death: some things the character must do when he dies.
• Animation Messages: When the player comes to close to the enemy, we need to play a walk back animation, when he’s translating or avoiding we need to play a run animation, when he’s firing we can play the stand shooting animation or the run shooting animation, and when he dies, well...we don’t need much animation for that (!).

This is about as simple as we can make it, which is good since in this action packed game we are aiming for quantity in enemies rather than quality in AI. In the screenshot you can see the structure of the AI script as it will look when we’re done.

12 Basic Behavior Create a script on your character called AI. Again, we have to start by making some new local parameters, which are all specific to the character the script is on:
“Enemy1 Bodypart”, Bodypart, Enemy1
“Enemy1 Spine1“, Bodypart, Enemy1 Spine1
“Enemy1 Muzzleflash”, 3D Sprite. Enemy1 Muzzleflash
“translation”, Boolean, True
“fire”, Boolean, True

• We also need to create a dummy object, in this case a 3D Frame, that is always a bit ahead of where the player is. We’ll use this as a target for the enemies to shoot at. So, create a new 3D Frame (with the toolbar), name it “dummy_target”. Create a small script on it, containing only a Set Position BB. Use a shortcut to current_translation (located in the translation BG inside the control script of the dummy character) as the Position pIn and set the dummy_character as the Referential. Loop this BB and connect it to Start. Back in the AI script, create one last local parameter for this 3D Frame: “dummy_target”, 3D Entity, dummy_target.

• It’s a good idea to keep the enemies Level Script open above the AI script, since we are going to use shortcuts to parameters in this script all the time. Now let’s get this script underway!

• Add an Add To Group BB to add the bodypart to the shootable_group. Add an Identity BB (set its pIn type to Boolean and the value to true) to set translation and fire to true and a Show BB ( Target: This). Insert an Object Slider BB (Radius:1, Group: objectslider_group). Add another Object Slider BB, setting the Radius to 2. Create a new group in the Level Manager, only containing the dummy_character bodypart (“dummy_character_group”), and specify this as the Group for this second Object Slider BB.

• Add an Unlimited Controller BB. Specify animation messages and the animations themselves in this order:
0 enemy1_walkbackwards_animation
1 enemy1_run_shoot_animation
2 enemy1_run_animation
3 enemy1_stand_shoot_animation
Be sure to check “Keep character on floor” and to set all framerates to 25!

• Create a BG “basic” around the whole lot, connecting only the second Object Slider BBs Contact bOut to the bOut of the BG.

13 Orientation Our enemy needs to keep an eye on the Hammer all the time. He also needs to have his body turned towards the Hammer all the time (so he just has to walk forward to approach him). However, there needs to be a little delay in the speed at which he can orientate (or else he’d be too difficult to beat because his weapon would always be pointing in the right direction!).

• Add a Delayer BB and a paramOp (Random), to create a random delay (0-3 seconds) in the activation of this orientation behavior (when the enemy spawns he will walk in the wrong direction for a second.
• Add an Interpolator BB (set its pOut type to vector and use Enemy1_orientation_speed as the Value pIn). This is going to interpolate between the characters current direction towards the direction looking directly at the player. Use a paramOp (Get Dir) to get this characters direction (use a This parameter) and insert the resulting vector into the first pIn of the Interpolator BB. To get the direction the enemy needs to be facing, we are going to use another paramOp (Get Position). Insert This as the left pIn and a shortcut to the dummy_target as the right pIn. Insert the resulting vector in another paramOp (Set Y) to set the Y of the vector to zero (we don’t want to rotate the character over its x-axis!). Insert the resulting vector as second pIn of the interpolator.

• Connect the pOut of the Interpolator BB into the Dir pIn of a new Set Orientation BB (Target: This).

• We are going to use the same method to orientate the Enemy1 Spine 1 (the spine of the character controls which way the character is looking with his upper body and also which way he will fire), only this time we ARE going to use the y of the vector (so the enemy can shoot up (when you’re standing on a car for example). Create the two BBs. Instead of the Set Y paramOp we are going to use an Addition paramOp, to add (0, 0.8, 0) to the value that comes out of the Get Position paramOp. This is to compensate for the spines weird own orientation. Also, set the Value pIn of the Interpolator to 30% (don’t use a shortcut to the “Enemy1_orientation_speed”). For the Set Orientation BB you have to set the Target to a shortcut to Enemy1 Spine1, the Dir pIn needs to be connected to the pOut of the interpolator and the Local Dir needs to be (0, 0, -1). The Local Up needs to be (1, 0, 0). Now loop it back to the first Interpolator BB. Create a BG around it called “orientation”.

Tip: When creating AI, it’s always good to add as much randomness as possible. If you use a Random paramOp to get a random time, be sure to use Time parameter types (Floats will be converted to milliseconds!).

14 Translation Now we’ve come to the tricky part of this tutorial. When should the enemy translate forward?
When his distance to the Hammer is greater than a randomly chosen amount and when our local parameter, “translation”, is true.

• Add a Binary Switch BB and three paramOps: Get Distance between This and the dummy_target. Insert the result into the left pIn of a Superior or Equal paramOp. Rename the right pIn to approach_distance and set its value to 7. Insert its result into the right pIn of a third paramOp (And). Insert a shortcut to “translation” into the left pIn. Insert that result into the Binary Switch BB.

• Now we need to create the translation behavior. Our enemy should move for a random time, while all the above conditions are true. First we need a Timer BB, combined with a Random paramOp to get the time (3 – 10 seconds). Loop it from the Loop out to Loop in. Now insert another Binary Switch BB, a Per Second BB (set the pOut to vector and insert the shortcut to Enemy1 Speed) and a Translate BB (set This as the Target and the Referential), set the pOut of the Per Second BB as the vector.

15 Translation Continued Now create a BG around the Timer BB, the Binary Switch BB, the Per Second BB and the Translate BB. Name it “approach”. Add two bOuts to this BG and construct one Boolean pIn (you can add pIns to a BG by pressing Alt+”I” when selected, or by using the rightclick menu). Via this pIn we must to connect the result of the And paramOp to the Binary Switch BB inside the “approach” BG as well. Connect the Timer BBs bOut to the lower bOut of the BG. Connect the False bOut of the Binary Switch BB to this lower bOut as well. Connect the Translate BBs bOut to the top bOut of the BG (if this link is active, the run animation needs to play).

• To create a more random behavior for our enemy, we are going to change the distance he keeps from the Hammer dynamically. Add a Delayer BB with a Random (1 – 4 seconds) paramOp. Now add a Random BB and paste a shortcut to Enemy1_approach_distance (you can find it in the “enemies” Level Script) above it. Connect it to the left pIn of the Random BB (select Get X in the paramOp pop-up) and connect it to the right pIn as well (select Get Y). Create a shortcut to approach_distance underneath the pOut and connect it. Create a BG around it called “rethink”

• Connect the True and False bOut of the Binary Switch BB to the bIn of the “rethink” BG. Connect the lower bOut of the “approach” BG to the bIn of the “rethink” BG as well. Loop the bOut of the “rethink” back to the Binary Switch BB. Connect the True bIn of the Binary Switch BB to the bIn of the “approach” BG. Now create a new BG for this part of your script called “translation”. Create a bOut for this BG as well. Connect this to the bOut of the “approach” BG. It’s pretty hard, check the screenshot if you’re not sure you’ve connected everything correctly!

Tip: The Random BB supports more pOut types than the Random paramOps.

16 Animation Messages Maybe now is a good time to create some Send Message BBs that handle the animations, even for behavior we haven’t scripted yet (so we can give our enemy a try!).

• Create three Send Message BBs underneath each other, “enemy1_walkbackwards_animation”, “enemy1_run_animation” and “enemy1_stand_shoot_animation” (set all Destination parameters to This). Create a BG around these BBs called “animation_messages”. This BG needs to have three bIns. Connect each bIn to a Send Message BB.

• When the bottom bIn, the one that is going to handle all fire behavior (the one now connected to “enemy1_stand_shooting”) is activated, we want our “enemy1_run_animation” (in the middle Send Message BB) to change into “enemy1_run_shoot_animation”. When the bIn stops being active, it needs to be set back. We’ll do this with a Stop&Go BB and a Parameter Selector BB (specify Message as the pOut Type, and specify “enemy1_run_animation” and “enemy1_run_shoot_animation” as the Messages). Connect you BBs as shown in the screenshot.

• Connect the bOut of the “basic” BG to the top bIn of the “animation_messages” BG and connect the bOut of the “translation” BG to the second /middle bIn.

• To give the enemies a try, be sure to check that the Enemy1 Character is Activated at scene start in the Level Manager (you have to set IC as well). Notice that the enemies don’t do anything when they should be shooting at you (they even play their animation a bit to long)! They also have the tendency to stick together. We’ll fix that first, and then we’ll handle the firing.

Tip: Set the “Enemy1_maximum” a little lower so you can inspect your character a bit better.

17 Avoid When the nearest character in the characters_activated_group is closer than 2 meters from our enemy, he should try to find a better place. This means we need to override the normal translation and (future) fire behavior (hence the “translation” and “fire” Booleans). Let’s create the condition first.

• Add a Get Nearest In Group BB (Group:characters_activated, Referential:This) and a Binary Switch BB with two paramOps.
These test if the Distance pOut of the Get Nearest In Group BB is Inferior Or Equal to “2” AND if “translation” is true. Loop the False bOut back to the Get Nearest In Group BB. Connect the True bOut to a new Identity BB (use it to set “translation” and “fire” to false).

• Now we need to pick a new random orientation for the enemy. Insert a Set Component BB and a Random paramOp (to pick a float between 0.9 and -0.9). Insert the result into Component 1 and 3 pIns of the Set Component BB. Create a new local vector parameter (“random_orientation”) underneath the BB and connect it to the pOut.

• For the temporary translation and orientation we first need a random Timer BB (using a paramOp 1 – 3 seconds). Loop it (Loop out – Loop in). Attach the Loop Out bOut to a new Per Second BB and a Translate BB (in the same way you did before, using the same parameters). Underneath those two BBs, create an Interpolator BB (also attached to the Loop Out bOut of the Timer BB) to interpolate between the orientation of This (use a Get Dir paramOp) and the random_orientation, using a Value of 50%. Connect the pOut to the Dir pIn of a new Set Orientation BB (Target:This). Now create a nice BG with two bOuts around it called “override”. Connect the Timer BB bOut to the top bOut and the Set Orientation BB or the Translate BB to the lower bOut.

• Behind the “override” BG, us an Identity BB to set “translation” and “fire” back to true. Add a Delayer BB (again using a Random paramOp, 1 – 4 seconds) and loop this behavior back to the Get Nearest In Group BB. Create another BG called “avoid” around this part of the script. Don’t forget to connect the lower bOut of that “override” to the bOut of the “avoid” BG.

• Connect the bOut of the “avoid” to the second bIn of the “animation_messages” BG. Test your script.

18 Return Fire The game will definitely be more fun if the enemies fire back (and we really need to stop that annoying moonwalk). The “fire” BG consists of three parts: the condition, the Animation Synchronizer and the firing of the bullet.

• Add a Binary Switch BB. Using paramOps, Get the Distance between This and the dummy_target, test if this float is Inferior or Equal to “Enemy1_fire_distance”AND if “fire” is true. I

• Create a Wait Message BB and an Animation Synchronizer BB. Connect the False bOut of the Binary Switch BB to the Off/Stop bIn of both BBs. Also loop it back to the bIn of the Binary Switch BB. Connect the True bOut to the On bIns of both BBs. Loop this one back to the bIn of the Binary Switch BB. Edit the Animation Synchronizer BB (the enemy must be visible!). We want a “enemy1_as_fire” message on frame 0 of the Enemy1_Stand_Shoot animation and on frame 0 and 10 of the Enemy1_Run_Shoot animation. Specify this same message for the Wait Message BB. Loop this BB.

• Create a Send Message BB (Target: Enemy1 Spine1, Message: enemy_fire Destination: Level). Add a Play Sound Instance BB. Specify the enemy1_glock as the sound and use a Get Position paramOp to feed it the position of the Enemy1 Spine1. Add a Show BB and a Hide BB, both using the Enemy1 Muzzleflash as their target. Set a link delay of 2 by double-clicking the link between the two. Create a BG “fire” around it. You need to connect the True bOut of the Binary Switch BB to the bOut of the new BG. Connect the bOut of the BG to the third bIn of the “animation_messages” BG.

• If this works, we have good news for you! The hardest part of the scripting is done! It’s going to be a walk in the park from now on…

19 Enemy Bullets Although we’re not ready with the AI yet, it’s probably a good idea to give the enemies some real bullets to play with.

• Go to the fire Level Script. Underneath the Wait Message BB, add another Wait Message BB (“enemy_fire”). Add a Get Message Data BB (use the same message). Create a new 3D Entity parameter (“enemy_sender”) and connect it to the pOut of the BB. Create an Identity BB (set the pIn type to 3D Entity) and use a paramOp to Get Element “1” of the “bullets_group”. Put the pOut of the Identity BB into a new 3D Entity parameter called “new_enemy_bullet”.

• Remove this bullet from the bullets_group group (Remove From Group BB). Use a Set Component BB and two random paramOps to create a new starting position for the bullet. The x needs to be between -0.2 and 0.5, the y between -0.4 and 0.4 and the z needs to remain 0.5. Use this vector as the Position pIn of a Set Position BB (Target: new_enemy_bullet, Referential: enemy_sender).
Create a Set Orientation BB (Target: new_enemy_bullet) and use a Get Dir paramOp to get the direction of the enemy_sender and insert it into the Dir pIn of the Set Orientation BB. The last thing we need to do is to add an Activate Object BB (Object: new_enemy_bullet, Activate All Scripts and Reset Scripts checked). Create a nice BG of all BBs after the Get Message Data BB and call it “enemy_bullet”. Don’t forget to loop this BG back to the Wait Message BB (I think the enemies need more than one bullet!).

• While we’re here, let’s insert a Send Message BB behind the Activate Object BB above (the one activating the shell_frame). We can use this later on the count the bullets the player has fired. Specify character_ammo_down as the message and Level as the Target.

• Two more things. Look up the script attached to the bullet object. It seems that we need to tweak the setting of the Ray Intersection BB in this script. The Ray Origin pIn needs to be set back to (0,0,0) and the Ray Depth to 2. We also have to make sure that the Hammer bodypart is in the shootable_group. If not, add it now and Set IC on this group. OK, test your script.

Tip: You may need to create more bullets (in the fire script). Also, if your composition is getting very sluggish, it may be a good idea to create fewer enemies.

20 Enemy Death Back to our AI script. We need to create one more BG.

• Insert a Wait Message BB (“object_dead”). Add a Set Position BB (Target:This, Position (0, -10, 0). Add a Add To Group BB (Target:This, Group: Enemy1 Group). Add a Remove From Group BB (Target:This, Group: Characters Activated Group). Another Remove From Group BB (Target: Enemy1 Spine1, Group: Shootable Group). Add a Deactivate Object BB (Target: This) and a Hide Hierarchy (Target:This). Create a BG called “death” around these BBs.

21 Analyzing The Impact Message Now we have scripted some behavior for when the enemy needs to die, we need to determine when he loses health and when his health is depleted. The bullet_impact message is handled in the “fire” Level Script, inside the “bullet impact” BG. This is where we have to analyze the message further, to see if the hit object is a character or an object.

• Before we create an impact mark, we first need to test what we are hitting, a character or an object. Delete the link between the Get Message Data BB and the Mark bIn of the Mark System BB. Move this last BB a bit more down) Insert a Has Attribute BB and set the attribute to object_health. Create a new local 3D Entity parameter underneath the Get Message BB, named “impact_object”. Connect it to the 3D Entity pOut. Maybe it’s a good idea to rename the Position and Normal parameters to “impact_position” and “impact_normal” and to position them underneath the Get Message BB as well. Use shortcuts to them for the Mark System BB pIns. Set the “impact_object” as the Target for the Has Attribute BB. Create a new float parameter “current_character_health” underneath the Has Attribute BBs pOut and connect it. Connect only the False bOut to the Mark System BBs Mark bIn. We don’t want to have a mark on our characters (otherwise we’d have to create a complex script to keep them positioned on the characters while they move around and animate). However, we’ve created a nicer mark for our other objects. In the texture setup for mark_default, drag mark_concrete.BMP from you resources onto the texture.

• Back to the scripting. If a character is hit, we don’t need the impact_frame creating rubble, we need some blood! Import the Sound misc_impact_flesh1.WAV and the Texture blood.BMP into your script. Now, in the Level Manager, create a copy of the impact_frame (Full dependencies) and rename it “blood_frame” (rename its script as well). In its script, specify the right sound for the Play Sound Instance BB. Edit the Point Particle System BB, specifying the blood as the Texture and specifying a nice red Initial Color for the particles.

• Back in the “bullet_impact” BG, insert two Activate Object BBs (one for the impact_frame and one for the blood_frame). Once again, be sure to check Activate All Scripts and Reset Scripts.
You can connect the bIn of the first one to the Mark System BBs Mark bOut (deleting all other links out of this bOut), the other one you can connect to the True bOut of the Has Attribute BB. Insert another Has Attribute BB behind the Activate Object BB for the impact_frame. Use it to test if the “impact_object” has an object_health attribute. Create a new local float parameter underneath its pOut called “current_object_health”) and connect it.

• The last thing we need to do is to send a message to the “score” Level Script that we’ve hit something. Create two Send Message BBs (“object_health_down” and “character_healh_down”), both with the Destination set to Level. The first one is linked to the Has Attribute BBs True bOut and the second is linked to the blood_frame Activate Object BBs bOut. To make sure this BG can run more than once, loop the Wait Message BB at the beginning of the script. You can delete the Activate Object BB outside the “bullet_impact” BG and the bOut of the BG.

Tip: Although more parameters makes your composition heavier on the processor, sometimes it’s clearer to use parameter shortcuts than to create a whole forest of crossing links. When your script works, always try to arrange you BBs in a way that is most clear for you.

22 Setting The Characters Health In the last step we send messages to the Level so that we can change the health attributes. We do this in the “score” Level Script, using shortcuts to parameters inside the “bullet_impact” BG.

• Create a new local float parameter called “bullet_damage” with a value of 50. In the “score” script insert a Switch On Message BB (“character_health_down” and “character_ammo_down”).
Add a Threshold BB, a Set Attribute BB (Target: impact_object, Attribute: character_health) and a Send Message BB (message: object_dead). Above the X pIn of the Threshold BB, add a paramOp (Subtraction). For the left pIn of the paramOp, use a shortcut to the current_character_health in the “fire” script. For the right pIn use a shortcut to “bullet_damage”. Insert the result into the Threshold BB. The Min pIn needs to remain “0”, the Max needs to be set to “1000”. You can connect the pOut to the “current_character_health” as well. Connect all bOuts to the Set Attribute BB, inserting the “current_character_health” as the value. Connect the X<MIN bOut to the Send Message BB. Set the parent Character (using a Get Parent paramOp) of the impact_object (bodypart) as the Destination for this message. Drag a BG around this called “character_health” and create two bOuts for this BG (one for the Set Attribute BB and one for the Send Message BB).

23 A Bloody Death OK, what else should happen when a character is hit? Nothing, unless the character is TheHammer, then we need to let the player know that he is hit using a camera filter. What else should happen when the characters health reaches zero? The character needs to die in a nice gory way (using a particle system). If the character is The Hammer, we probably need to create some sort of Retry script, but we’ll handle that later.

• First, drag camerafilter_blood.BMP into your composition. Create a new Level Script called “interface”. Add a looped Wait Message BB (message: camerafilter_blood) into this script. Add a Delayer BB (100 ms) and a Planar Filter BB. Connect the bOut of the Wait Message BB to the bIn of the Delayer BB and the Planar Filter BB. Connect the bOut of the Delayer BB to the Off bIn of the Planar Filter BB. Create a BG around it called “camerafilter_blood”.

• Now drag flesh_frame.NMO from your 3D Entities Resources into the composition. This file contains a 3D Frame (flesh_frame) with two Point Particle Systems and another Mark System. It also contains a material, a texture and two sounds. It creates a “gib” effect when you send it a message (“flesh”). In the script attached to flesh_frame, specify the shootable_group in the Ray Intersection BB. Specify the “blood” for the texture in the upper Point Particle System BB. We’ll take a closer look at particle systems in the next tutorial.

• Back in the score script, insert two Switch On Parameter BBs. Both of them need to test if the impact_object is “TheHammer” bodypart (you need to set the pIn type of the BB to 3D Entity). Connect the upper BBs Out1 bOut to a new Send Message BB (Message: camerafilter_blood, Destination: Level).

• Behind the lower Switch On Parameter BBs None bOut, add a Set Postion BB (Target: flesh_frame, Position (0, 1.5, 0) and Referential: impact_object). Behind that, add a Send Message BB (Message:: flesh, Target: flesh_frame). Now add another Send Message BB (Message: give_item, Destination: Level). This message needs a vector (where the items should be), so construct a vector pIn for the Send Message BB (using the rightclick menu). Use a paramOp (Get Position) to get the location of the impact_object, then use another paramOp (Addition) to add (0, 1, 0) to this. Insert the result in the new vector pIn of the BB.

• When the Hammer dies, the Out1 bOut of the lower Switch On Parameter BB is activated. Behind it, add a Set Position BB (Target: flesh_frame, Position (0,0,0) and Referential: dummy_character). Add a Send Message BB (Message: flesh, Destionation: flesh_frame). Create a BG “hit_or_dead”with two bIns around this part of the script. Connect it so that the top bOut of the “character_health” BG activates the upper bIn of the “hit_or_dead” BG, and the lower bOut activates the lower bIn. (see screenshot). Although the Hammer won’t disappear yet, you can give your script a try!

Your composition now has all the ingredients of a real game! In the next tutorial we’ll add some more effects, fix some bugs and prepare it for online publishing!

End of part 4.

You can continue with part 5 or
return to the overview.