| 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. You can continue with your own project or open tutorial_part_4_start.CMO.
|
|||||||
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. |
![]() |
||||||
|
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. • 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: • 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. | ![]() |
||||||
|
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. • 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: • 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. • 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! | ![]() |
||||||
![]() |
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!).
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. • 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.
| ![]() |
||||||
![]() |
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_approach_distance”, Vector2D, (7, 12) “Spawner_maximum”, Float, 25 • 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. |
||||||
| 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: • 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. • 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”.
|
![]() |
||||||
![]() |
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!
| ![]() |
||||||
![]() |
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.
|
||||||
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. • 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). • 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.
|
![]() |
||||||
![]() |
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. • 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.
|
![]() |
||||||
![]() |
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”). |
||||||
| 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
|
||||||