Entity communication (ActionScript tutorial): Difference between revisions

From Whirled Club Wiki
Jump to navigation Jump to search
(Created page with "{{Infobox tutorial |type=ActionScript |difficulty=Intermediate |description=Create an interactive pet using AS3. |requirements=20px ActionScri...")
 
m (Text replacement - """ to """)
 
(2 intermediate revisions by the same user not shown)
Line 19: Line 19:
You can use EntityControl.addEventListener() to listen for [http://whirled.com/code/asdocs/com/whirled/EntityControl.html#event:entityEntered entityEntered], [http://whirled.com/code/asdocs/com/whirled/EntityControl.html#event:entityEntered entityMoved] and [http://whirled.com/code/asdocs/com/whirled/EntityControl.html#event:entityEntered entityLeft] events:
You can use EntityControl.addEventListener() to listen for [http://whirled.com/code/asdocs/com/whirled/EntityControl.html#event:entityEntered entityEntered], [http://whirled.com/code/asdocs/com/whirled/EntityControl.html#event:entityEntered entityMoved] and [http://whirled.com/code/asdocs/com/whirled/EntityControl.html#event:entityEntered entityLeft] events:


<actionscript>
<actionscript>
_ctrl = new PetControl(this);
_ctrl = new PetControl(this);
_ctrl.addEventListener(ControlEvent.ENTITY_MOVED, handleMovement);
_ctrl.addEventListener(ControlEvent.ENTITY_MOVED, handleMovement);
Line 25: Line 25:
function handleMovement (event :ControlEvent) :void
function handleMovement (event :ControlEvent) :void
{
{
     _ctrl.sendChat(&quot;Something's moving around!&quot;);
     _ctrl.sendChat("Something's moving around!");
}
}
&lt;/actionscript&gt;
</actionscript>


== Requesting Properties ==
== Requesting Properties ==
Line 33: Line 33:
The ControlEvent contains the entity ID of the mover, we can use that to access properties on that entity using EntityControl.getEntityProperty():
The ControlEvent contains the entity ID of the mover, we can use that to access properties on that entity using EntityControl.getEntityProperty():


&lt;actionscript&gt;
<actionscript>
function handleMovement (event :ControlEvent) :void
function handleMovement (event :ControlEvent) :void
{
{
Line 39: Line 39:


     // Use getEntityProperty() to query the target's name
     // Use getEntityProperty() to query the target's name
     _ctrl.sendChat(&quot;I see you &quot; + _ctrl.getEntityProperty(EntityControl.PROP_NAME, targetId));
     _ctrl.sendChat("I see you " + _ctrl.getEntityProperty(EntityControl.PROP_NAME, targetId));
}
}
&lt;/actionscript&gt;
</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:
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:


&lt;actionscript&gt;
<actionscript>
function handleMovement (event :ControlEvent) :void
function handleMovement (event :ControlEvent) :void
{
{
Line 52: Line 52:
     // IMPORTANT: We will receive events from our own movements, so make sure we don't handle them here
     // IMPORTANT: We will receive events from our own movements, so make sure we don't handle them here
     if (targetId != _ctrl.getMyEntityId()) {
     if (targetId != _ctrl.getMyEntityId()) {
         _ctrl.sendChat(&quot;I see you &quot; + _ctrl.getEntityProperty(EntityControl.PROP_NAME, targetId));
         _ctrl.sendChat("I see you " + _ctrl.getEntityProperty(EntityControl.PROP_NAME, targetId));
          
          
         // Follow it
         // Follow it
Line 59: Line 59:
     }
     }
}
}
&lt;/actionscript&gt;
</actionscript>


== Custom Property Providers ==
== Custom Property Providers ==
Line 65: Line 65:
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.
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.


&lt;actionscript&gt;
<actionscript>
// In Food.as
// In Food.as


Line 73: Line 73:
function propertyProvider (key :String) :Object
function propertyProvider (key :String) :Object
{
{
     if (&quot;tutorial:takeFood&quot; == key) {
     if ("tutorial:takeFood" == key) {
         // Something in the room is requesting food from me, send back a random amount
         // Something in the room is requesting food from me, send back a random amount
         return Math.floor(Math.random()*20) + 1;
         return Math.floor(Math.random()*20) + 1;
Line 81: Line 81:
     return null;
     return null;
}
}
&lt;/actionscript&gt;
</actionscript>


Let's modify our pet to look for food when someone in the room says &quot;go eat&quot;:
Let's modify our pet to look for food when someone in the room says "go eat":


&lt;actionscript&gt;
<actionscript>
// In Dog.as
// In Dog.as


Line 92: Line 92:
function handleChat (event :ControlEvent) :void
function handleChat (event :ControlEvent) :void
{
{
     if (event.value == &quot;go eat&quot;) {
     if (event.value == "go eat") {
         // Get all the furniture/toys IDs in the room
         // Get all the furniture/toys IDs in the room
         var furnis :Array = _ctrl.getEntityIds(EntityControl.TYPE_FURNI);
         var furnis :Array = _ctrl.getEntityIds(EntityControl.TYPE_FURNI);
Line 98: Line 98:
         for each (var id :String in furnis) {
         for each (var id :String in furnis) {
             // Try to ask for some food
             // Try to ask for some food
             var food :Number = _ctrl.getEntityProperty(&quot;tutorial:takeFood&quot;, id) as Number;
             var food :Number = _ctrl.getEntityProperty("tutorial:takeFood", id) as Number;


             // If food was returned
             // If food was returned
             if (food &gt; 0) {
             if (food > 0) {
                 _ctrl.sendChat(&quot;*munch munch*&quot;);
                 _ctrl.sendChat("*munch munch*");


                 // Walk over to the food bowl
                 // Walk over to the food bowl
Line 113: Line 113:


         // If we reach this point, we didn't find anything edible
         // If we reach this point, we didn't find anything edible
         _ctrl.sendChat(&quot;I can't find anything to eat... *whimper*&quot;);
         _ctrl.sendChat("I can't find anything to eat... *whimper*");
     }
     }
}
}
&lt;/actionscript&gt;
</actionscript>


=== Calling Remote Functions ===
=== 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 &quot;attackForDamage&quot; message along with the amount of damage it is trying to inflict. In this hypothetical case, a slayable Dragon pet would listen for &quot;attackForDamage&quot; and respond:
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:


&lt;actionscript&gt;
<actionscript>
// In Dragon.as
// In Dragon.as


Line 128: Line 128:
function propertyProvider (key :String) :Object
function propertyProvider (key :String) :Object
{
{
     if (key == &quot;attackForDamage&quot;) {
     if (key == "attackForDamage") {
         // Don't actually do anything yet
         // Don't actually do anything yet
         // Return a Function object that the Knight can use to damage the dragon
         // Return a Function object that the Knight can use to damage the dragon
         return function (damage :Number) :void {
         return function (damage :Number) :void {
             _ctrl.sendChat(&quot;Ouch! A Knight hit me for &quot; + x + &quot; damage!&quot;);
             _ctrl.sendChat("Ouch! A Knight hit me for " + x + " damage!");
         }
         }
     }
     }
Line 138: Line 138:
     return null;
     return null;
}
}
&lt;/actionscript&gt;
</actionscript>


&lt;actionscript&gt;
<actionscript>
// In Knight.as
// In Knight.as


var dragonId :String = ... // The entity ID of a Dragon
var dragonId :String = ... // The entity ID of a Dragon
var attackForDamage :Function = _ctrl.getEntityProperty(&quot;attackForDamage&quot;, dragonId) as Function;
var attackForDamage :Function = _ctrl.getEntityProperty("attackForDamage", dragonId) as Function;


// Attack the Dragon for 30 damage
// Attack the Dragon for 30 damage
attackForDamage(30);
attackForDamage(30);


// Or... have damage be based on your Knight's &quot;level&quot;
// Or... have damage be based on your Knight's "level"
attackForDamage(10 * (_ctrl.getMemory(&quot;level&quot;) as Number));
attackForDamage(10 * (_ctrl.getMemory("level") as Number));
&lt;/actionscript&gt;
</actionscript>


== Helper Class: RemoteEntity ==
== Helper Class: RemoteEntity ==
Line 157: Line 157:
If your project use entity properties heavily, consider using the convenient [http://whirled.com/code/contrib/asdocs/com/whirled/contrib/RemoteEntity.html RemoteEntity] class instead of direct calls to EntityControl.getEntityProperty():
If your project use entity properties heavily, consider using the convenient [http://whirled.com/code/contrib/asdocs/com/whirled/contrib/RemoteEntity.html RemoteEntity] class instead of direct calls to EntityControl.getEntityProperty():


&lt;actionscript&gt;
<actionscript>
// RemoteEntity example snippet:
// RemoteEntity example snippet:


Line 163: Line 163:
var remote :RemoteEntity = new RemoteEntity(_ctrl, targetId);
var remote :RemoteEntity = new RemoteEntity(_ctrl, targetId);


// Same as trace(&quot;Hello &quot; + _ctrl.getEntityProperty(EntityProperty.PROP_NAME, targetId) as String))
// Same as trace("Hello " + _ctrl.getEntityProperty(EntityProperty.PROP_NAME, targetId) as String))
trace(&quot;Hello &quot; + remote.getName());
trace("Hello " + remote.getName());


// Same as (_ctrl.getEntityProperty(&quot;attackForDamage&quot;, targetId) as Function)(50);
// Same as (_ctrl.getEntityProperty("attackForDamage", targetId) as Function)(50);
remote.call(&quot;attackForDamage&quot;, 50);
remote.call("attackForDamage", 50);
&lt;/actionscript&gt;
</actionscript>





Latest revision as of 21:34, 5 September 2018

ActionScript Tutorial
Create an interactive pet using AS3.
Difficulty Level
Intermediate
Requirements
Icon-Programming.png ActionScript 3.0, Whirled SDK
Other Information
Other tutorials: Talking pet (ActionScript tutorial)
Icon-highlighted-pet.png

This tutorial uses AS3 to build a smart pet that is able to detect and interact with other items in the room.

Prerequisites

  1. Setting up your programming environment
  2. 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:

Template:Room

External links