An Intent can have an Action associated with it. This action will be executed when the intent is matched at runtime. Actions should extend the LexiconAction class and override the Process
method. The simplest way to create an action is to click the Create Action button on an intent asset.
LexiconAction is a component, and must be attached to a prefab before it can be associated with an intent. The Create Action button will automatically create the action script and the action prefab for you.
Actions are not associated with any one scene. They cannot reference objects in your scenes, except via searching at runtime. Treat them as reusable functionality that should work across multiple scenes. If you need to reference scene objects, use an Intent Handler instead.
The best way to learn about writing actions is to review the sample actions. Here’s the Create Primitive action:
using UnityEngine;
// Shorthand for the auto-generated strings belonging to this intent.
using Strings = Mixspace.Lexicon.Actions.CreatePrimitiveStrings;
namespace Mixspace.Lexicon.Actions
{
public class CreatePrimitiveAction : LexiconAction
{
public Shader shader;
public override bool Process(LexiconRuntimeResult runtimeResult)
{
// There may be multiple primitives, break the phrase up by primitive entity.
// E.g. "Create a red cube here and a blue sphere here."
foreach (LexiconEntityMatch primitiveMatch in runtimeResult.GetEntityMatches(Strings.Primitive))
{
PrimitiveType primitiveType = primitiveMatch.EntityValue.GetBinding<PrimitiveType>();
Material material = new Material(shader);
// We expect the color entity (if present) to come before the primitive entity.
LexiconEntityMatch colorMatch = runtimeResult.GetEntityBefore(Strings.Color, primitiveMatch);
if (colorMatch != null)
{
material.color = colorMatch.EntityValue.GetBinding<Color>();
}
// Create the primitive. Use a container to anchor from the bottom.
GameObject container = new GameObject(primitiveType.ToString());
GameObject primitive = GameObject.CreatePrimitive(primitiveType);
primitive.GetComponent<Renderer>().material = material;
float yOffset = primitive.GetComponent<Renderer>().bounds.extents.y;
primitive.transform.parent = container.transform;
primitive.transform.localPosition = new Vector3(0.0f, yOffset, 0.0f);
container.transform.localScale = new Vector3(0.2f, 0.2f, 0.2f);
container.AddComponent<LexiconSelectable>();
// We expect the position (if present) to come after the primitive entity.
LexiconEntityMatch positionMatch = runtimeResult.GetEntityAfter(Strings.Position, primitiveMatch);
if (positionMatch != null && positionMatch.FocusPosition != null)
{
// Use the focus position of the position entity if present.
container.transform.position = positionMatch.FocusPosition.Position;
}
else if (primitiveMatch.FocusPosition != null)
{
// Otherwise use the focus position of the primitive enity.
container.transform.position = primitiveMatch.FocusPosition.Position;
}
else
{
// As a fall back we can place the object in front of the camera.
Camera mainCamera = Camera.main;
if (mainCamera != null)
{
container.transform.position = mainCamera.transform.position + mainCamera.transform.forward * 2.0f;
}
}
}
// We've consumed this intent, return true to prevent other handlers from firing.
return true;
}
}
}