Mission and Avatar Scripting

Mission and Avatar Scripting

 

Creating a derived copy of droid and scripting:

Create a separate copy of droid and name it "NewAssaultDroid". To do this, open the context menu for AssaultDroid and select "Create Derived Copy". Then rename created droid.
 

1) Random scaling of droid at damage. Attaching RandomResize action on EntityDamaged trigger.




 
Open Damaged trigger in WE. And drag drop Attack action on ForceSuccess decorator, as shown in the video. (Because the trigger is a parallel action, it will wait for the completion of all of their actions-children, and we need to force terminate Attack action. More information about Behavior Trees: http://aigamedev.com/open/articles/bt-overview/ )
 
Then drag and drop RandomResize action on trigger. You can configure the properties of RandomResize in Object Explorer.
 
Save droid.
 
See also the example of actions creation in C #:
 

2) Using in CTF: Custom scripted droid for RobotWarGame.


 
Drag and drop RobotWarGame scenario (from AE-> Scripting-> Scenarios) on Scene.
Scenario appears in WE. Select it and open in Object Editor. Set NewAssaultDroid as SpawnPrefab property.
 
Save the scene. It is useful for the following steps.
 
Additional information about Setup spawn prefab:
 
Start the game (Battle Manager Console-> Start Battle). Now droid will change the size if damaged.
 

3) Creating of a tree on the place of droid death. Attaching CreateEntity action on EntityDied trigger.



 
Reload scene. We saved it in point 2, and it appears with scenario.
 
Drag and drop EntityDied event on NewAssaultDroid.
Drag and drop CreateEntityOnOwnerPosition on created EntityDiedTrigger trigger. (CreateEntityOnOwnerPosition is a decorator and modifies CreateEntity action, that entity was created in position of action owner)
 
Select CreateEntity action and set “AE->Entities->Vegetation->MediumTree” (for example) as EntityType property in Object Explorer.
Uncheck “HeightRelativeToGround”.
 
Save entity and set it as SpawnPrefab, as you did in point 2.
 
Start game and test.
 

4) Switching to a new weapon. And the addition of new custom events from C#: Delivery and Capture the flag.



 
At this point, we add two triggers, and for droid, who captured the flag, will activate WaterBall super weapon.
 
Reload scene.
 
In Visual Studio, add a new event class FlagDelivered. Inherit it from BaseSelfEvent. Here is the full code for the class:
 
public class FlagDelivered : BaseSelfEvent
{
public FlagDelivered()
{
}

public FlagDelivered(EntityBase self)
: base(self)
{
}

public FlagDelivered(EntityParam self)
: base(self)
{
}

public override string ToString()
{
return string.Format("Flag delivered by {0}", Self);
}
}
 
Similarly, add a new FlagCaptured class:

public class FlagCaptured : BaseSelfEvent
{
public FlagCaptured()
{
}

public FlagCaptured(EntityBase self)
: base(self)
{
}

public FlagCaptured(EntityParam self)
: base(self)
{
}

public override string ToString()
{
return string.Format("Flag captured by {0}", Self);
}
}
 
Open scenario file RobotWarGame.cs. Find TakeFlag method and add this code at the end of the method:
 
var em = EventManager.Instance;
em.TriggerEvent(new FlagCaptured(captor));
 
This code generates your new event.
 
Find DeliveFlag method and add at the end:
 
var em = EventManager.Instance;
em.TriggerEvent(new FlagDelivered(captor));
 
Build project/solution. The project should be builded without errors.
 
Start the engine and load scene.
 
Your created event will appear in the AE-> Scripting-> Events. Drag them to NewAssaultDroid. Then drag and drop ChangeMissileType action on created triggers.
 
Select ChangeMissileType for FlagCapturedTrigger and select WaterBall as WeaponType propertie. For FlagDeliveredTrigger ChangeMissileType selected WeaponType = Missile by default.
 
Save entity and set it as SpawnPrefab, as you did in point 2.
 
Start game and test.
 

5) Modification of EntityKilled trigger by using action on the IronPython. A tree grows only where the droid with the flag was destroyed.



 
Toolset has support built-in scripting language. We can write small scripts without using Visual Studio. Here we modify EntityKilled trigger and add a condition with check on ownership of the flag.
 
Reload scene.
 
Modify Main module script. This script is always run at scene startup. It is located in WE-> Modules. To do this, click on it twice and it will open in Script Editor. Add code:
 
import Visual3D.Demo.Scripting.API.SCTFGame
from Visual3D.Demo.Scripting.API.SCTFGame import *
 
Save script in the editor.
 
Create a new action in Python. To do this, find AE-> Scripting-> Behaviors-> Actions-> PythonActions-> PythonAction and create derived copy via context menu. Name the new script “CreateTree”.
 
Open it in ScriptEditor and type the code:
 
if IsFlagCaptor(_self):
        Create(None, "MediumTree", None, GetPosition(_self), GetRotation(_self) , 1.0, True, False)
 
In the editor you can use snippets with all the possible commands. These are available via the context menu.
 
IsFlagCaptor(...) - a condition that checks whether the entity owns the flag.
Create(...) - creates a new entity. Similarly to action CreateEntity.
_self - in this variable will be placed entity to which to apply the script.
 
Save script in editor and in Asset Explorer.
 
Select NewAssaultDroid and open EntityDiedTrigger. Delete CreateEntityOnOwnerPosition action. And drag drop your script instead.
 
Save entity and set it as SpawnPrefab, as you did in point 2.
 
Start game and test.
 
In addition:
 

Addition of custom Ability. CTFStatistics ability.


 
Entities consist of components or abilities. For example in the engine already has such ability as Inventory, Combatant, GameParameters, Perception, Physics.
 
We'll create our ability in the code. It will collect combat statistics for the following parameters:
 
  • The number of shots.
  • The number of damages.
  • The number of killed droids.
  • The number of captured flags.
  • The number of delivered flags.
Statistics will be displayed on the screen at pressing the "I" button. (you should control entity at this time)
 
Add a new class CTFStatistics. Inherit it from Ability. In method OnActivated we add event handlers required for statistics. In method OnUpdated we expect to pressing the "I" and displays statistics on the screen.
 
The class should be marked by attribute [DataContract]. And properties by [DataMember].
 
The full code of class:
 
[DataContract]
public class CTFStatistics : Ability
{
[DataMember]
public int Shots { get; set; }

[DataMember]
public int Damages { get; set; }

[DataMember]
public int Kills { get; set; }

[DataMember]
public int CapturedFlags { get; set; }

[DataMember]
public int DeliveredFlags { get; set; }

static CTFStatistics()
{
Runtime.TypeConversion.RegisterExpandableType(typeof(CTFStatistics), true);
}

public CTFStatistics()
: base("CTFStatistics")
{
}

protected override void OnActivated()
{
base.OnActivated();

var inv = OwnerEntity.Get<Inventory>();
if (inv != null) {
var missileLauncher = inv.MainWeapon as Weapon.MissileLauncher;
if (missileLauncher != null)
missileLauncher.Launched += (s, e) => Shots++;
}

var em = EventManager.Instance;
em.EventTriggered += new EventHandler<BaseEventArgs>(EventTriggered);
}

protected override void OnDeactivated()
{
base.OnDeactivated();

Shots = 0;
Damages = 0;
Kills = 0;
CapturedFlags = 0;
DeliveredFlags = 0;
}

private void EventTriggered(object sender, BaseEventArgs e)
{
if (e.Event is EntityDamaged)
{
var evnt = (EntityDamaged)e.Event;
if (evnt.Target != null && evnt.Target.GetEntity() == OwnerEntity)
Damages++;
}

if (e.Event is EntityDied)
{
var evnt = (EntityDied)e.Event;
if (evnt.Target != null && evnt.Target.GetEntity() == OwnerEntity)
Kills++;
}

if (e.Event is FlagCaptured)
{
var evnt = (FlagCaptured)e.Event;
if (evnt.Self.GetEntity() == OwnerEntity)
CapturedFlags++;
}

if (e.Event is FlagDelivered)
{
var evnt = (FlagDelivered)e.Event;
if (evnt.Self.GetEntity() == OwnerEntity)
DeliveredFlags++;
}
}

protected override void OnUpdated()
{
base.OnUpdated();

if (!OwnerEntity.VisualObject().IsFocused)
return;

if (World.InputReader.AreAnyKeysPressed(Key.I)) {

string stats = string.Empty;
stats += "Shots: " + Shots + "\n";
stats += "Damages: " + Damages + "\n";
stats += "Shots: " + Shots + "\n";
stats += "Kills: " + Kills + "\n";
stats += "CapturedFlags: " + CapturedFlags + "\n";
stats += "DeliveredFlags: " + DeliveredFlags + "\n";

World.Gui.TextHandlers.WriteLines(Visual3D.UI.GuiScreen.CaptionTextId, stats.Split('\n'));
}
}
}
 
Build projects and start engine.
 
New ability will automatically be added: AE-> Scripting-> Abilities-> CTFStatistics
 
Drag and drop it on NewAssaultDroid. Note: There are several ways to add components to the entity. For example: 1) Drag and drop. 2) Entity context menu 3) And Object Explorer. See video tutorial. You can use the most convenient way for you.
 
Save entity and set it as SpawnPrefab, as you did in point 2.
 
Start game and test. Statistics will be displayed on the screen, at pressing the "I". (you should control entity at this time)
 

Creation of custom DroidPlayer class derived from AssaultDroid from code. Addition of Statistics ability. Addition of triggers and actions from code.

 
 
All that scripting, which we have done in the preceding points can be coded in the code on C#. To do this we will create DroidPlayer class, derived from AssaultDroid, and add ability and triggers, which we added in the previous points.
 
Add a new class DroidPlayer. Inherit it from AssaultDroid. In method OnConstructedadd triggers and ability. This method will be executed only when adding entity in Asset Explorer database. This means that in the future, you can modify the trigger/ability through toolset. Changes will not be lost.
 
We also add CTFStatistics property to DroidPlayer class. And mark its by PropertyCategory attribute and by Browsable to CTFStatistics appear as a category in the Object Explorer.
 
The class should be marked by attribute [DataContract].
 
Full code of class:
 
[DisplayName("DroidPlayer")]
public class DroidPlayer : AssaultDroid
{
[Browsable, PropertyCategory("CTF Statistics")]
public CTFStatistics CTFStatistics
{
get { return Get<CTFStatistics>(); }
}

public DroidPlayer()
{ }

protected override void OnConstructed()
{
base.OnConstructed();

// CTFStatistics

GetOrCreate<CTFStatistics>();

// Random Resize Trigger

var randomResizeTrigger = GetAction("Damaged") as Trigger;
randomResizeTrigger.Event = new EntityDamaged();
randomResizeTrigger.Actions.Clear();
randomResizeTrigger.Actions.Add(new ForceSuccess(new Attack()));
randomResizeTrigger.Actions.Add(new RandomResize(new Range<float>(0.5f, 3.0f)));
AddAction(randomResizeTrigger);

// Tree On Droid Kill

var treeOnDroidKillTrigger = new Trigger("TreeOnDroidKillTrigger");
treeOnDroidKillTrigger.Event = new EntityDied();
var onpos = new CreateEntityOnOwnerPosition();
var ce = (CreateEntity)onpos.Action;
var info = Library.Database.GetAssetByDisplayName("MediumTree");
ce.EntityType = new SceneEntityRef<EntityBase>(info.GetLoadedAsset<EntityBase>(InstancingMode.Instanced));
treeOnDroidKillTrigger.Actions.Add(onpos);
AddAction(treeOnDroidKillTrigger);

// Changing Missile Type if Flag Captured/Delivered.

var flagDeliveredTrigger = new Trigger("FlagDeliveredTrigger");
flagDeliveredTrigger.Event = new FlagDelivered();
flagDeliveredTrigger.Actions.Add(new ChangeMissileType(Weapon.MissileType.Rocket));
AddAction(flagDeliveredTrigger);

var flagCapturedTrigger = new Trigger("FlagCapturedTrigger");
flagCapturedTrigger.Event = new FlagCaptured();
flagCapturedTrigger.Actions.Add(new ChangeMissileType(Weapon.MissileType.WaterBall));
AddAction(flagCapturedTrigger);
}
}
 
Build projects and start engine.
 
To add DroidPlayer in AE. Open the context menu on a folder OE-> Entities and select "Add New Custom Type". In the window that appears, check "Inspect All Visual 3D Assemblies" and select DroidPlayer in list. Press "Create".
 
In the AE will be a new entity. You can drag and drop it on scene and look at its properties in the WE. There will be triggers, and ability that we have added in code. In Object Explorer you will see the "CTF Statistics" category.
 
Save entity and set it as SpawnPrefab, as you did in point 2.
 
Start game and test.
 
Tutorial is over.