Entity communication (ActionScript tutorial)
| ActionScript Tutorial |
|---|
| Create an interactive pet using AS3. |
| Difficulty Level |
| Intermediate |
| Requirements |
| Other Information |
| Other tutorials: Talking pet (ActionScript tutorial) |
This tutorial uses AS3 to build a smart pet that is able to detect and interact with other items in the room.
Prerequisites
- Setting up your programming environment
- This tutorial currently assumes you are familiar with programming and that you can learn by example.
Entity Events
In Whirled, every item (toys, pets, avatars, backdrops...) is called an entity. Every copy of your item in Whirled has its own unique entity ID.
You can use EntityControl.addEventListener() to listen for entityEntered, entityMoved and entityLeft events:
<actionscript> _ctrl = new PetControl(this); _ctrl.addEventListener(ControlEvent.ENTITY_MOVED, handleMovement);
function handleMovement (event :ControlEvent) :void {
_ctrl.sendChat("Something's moving around!");
} </actionscript>
Requesting Properties
The ControlEvent contains the entity ID of the mover, we can use that to access properties on that entity using EntityControl.getEntityProperty():
<actionscript> function handleMovement (event :ControlEvent) :void {
var targetId :String = event.name;
// Use getEntityProperty() to query the target's name
_ctrl.sendChat("I see you " + _ctrl.getEntityProperty(EntityControl.PROP_NAME, targetId));
} </actionscript>
Now our pet will announce when it sees an avatar (or another pet) moving in the room. Let's improve this a bit to make the pet follow any movement:
<actionscript> function handleMovement (event :ControlEvent) :void {
var targetId :String = event.name;
// IMPORTANT: We will receive events from our own movements, so make sure we don't handle them here
if (targetId != _ctrl.getMyEntityId()) {
_ctrl.sendChat("I see you " + _ctrl.getEntityProperty(EntityControl.PROP_NAME, targetId));
// Follow it
var pos :Array = _ctrl.getEntityProperty(EntityControl.PROP_LOCATION_PIXEL, targetId) as Array;
_ctrl.setPixelLocation(pos[0], pos[1], pos[2], 0);
}
} </actionscript>
Custom Property Providers
Let's make a food bowl that our pet can go to when he's hungry. The food bowl will be a separate toy item, and can use a property provider to respond to our pet when he asks for food.
<actionscript> // In Food.as
_ctrl = new FurniControl(this); _ctrl.registerPropertyProvider(propertyProvider);
function propertyProvider (key :String) :Object {
if ("tutorial:takeFood" == key) {
// Something in the room is requesting food from me, send back a random amount
return Math.floor(Math.random()*20) + 1;
}
// We don't support this key, so return null return null;
} </actionscript>
Let's modify our pet to look for food when someone in the room says "go eat":
<actionscript> // In Dog.as
_ctrl.addEventListener(ControlEvent.RECEIVED_CHAT, handleChat);
function handleChat (event :ControlEvent) :void {
if (event.value == "go eat") {
// Get all the furniture/toys IDs in the room
var furnis :Array = _ctrl.getEntityIds(EntityControl.TYPE_FURNI);
for each (var id :String in furnis) {
// Try to ask for some food
var food :Number = _ctrl.getEntityProperty("tutorial:takeFood", id) as Number;
// If food was returned
if (food > 0) {
_ctrl.sendChat("*munch munch*");
// Walk over to the food bowl
var pos :Array = _ctrl.getEntityProperty(EntityControl.PROP_LOCATION_PIXEL, id) as Array;
_ctrl.setPixelLocation(pos[0], pos[1], pos[2], 0);
return;
}
}
// If we reach this point, we didn't find anything edible
_ctrl.sendChat("I can't find anything to eat... *whimper*");
}
} </actionscript>
Calling Remote Functions
Property providers allows an entity to respond to simple messages passed to it. In this case, the messages are just strings. What if we want to specify parameters in the message? For example, a Knight avatar may send an "attackForDamage" message along with the amount of damage it is trying to inflict. In this hypothetical case, a slayable Dragon pet would listen for "attackForDamage" and respond:
<actionscript> // In Dragon.as
_ctrl.registerPropertyProvider(propertyProvider); function propertyProvider (key :String) :Object {
if (key == "attackForDamage") {
// Don't actually do anything yet
// Return a Function object that the Knight can use to damage the dragon
return function (damage :Number) :void {
_ctrl.sendChat("Ouch! A Knight hit me for " + x + " damage!");
}
}
return null;
} </actionscript>
<actionscript> // In Knight.as
var dragonId :String = ... // The entity ID of a Dragon var attackForDamage :Function = _ctrl.getEntityProperty("attackForDamage", dragonId) as Function;
// Attack the Dragon for 30 damage attackForDamage(30);
// Or... have damage be based on your Knight's "level" attackForDamage(10 * (_ctrl.getMemory("level") as Number)); </actionscript>
Helper Class: RemoteEntity
If your project use entity properties heavily, consider using the convenient RemoteEntity class instead of direct calls to EntityControl.getEntityProperty():
<actionscript> // RemoteEntity example snippet:
// Set up a remote targeting a certain entity var remote :RemoteEntity = new RemoteEntity(_ctrl, targetId);
// Same as trace("Hello " + _ctrl.getEntityProperty(EntityProperty.PROP_NAME, targetId) as String)) trace("Hello " + remote.getName());
// Same as (_ctrl.getEntityProperty("attackForDamage", targetId) as Function)(50); remote.call("attackForDamage", 50); </actionscript>
Demo
Mr Fusspot gets hungry quickly, but he's happy to play with visitors when he has the energy:
External links
- Smart Pet source: Complete source for the pet and food bowl in this tutorial.
- Face Hugger source: Another pet that tracks players around the room.
- Ant colony source: A complex example of interaction between an avatar, a pet and a toy.