ActionScript 3.0: Finite State Machine–with Global State


1. Pendahuluan
Di sini saya hanya akan menjelaskan sedikit modifikasi yang dapat dilakukan pada FSM. Langsung saja pada pokok permasalahannya: Pada FSM yang telah dibahas sebelumnya, FSM ini ternyata mempunyai beberapa kelemahan, salah satunya adlaah yang dikenal dengan sebutan “Alarm Behaviour”.

funny-robot

Apa itu “Alarm Behaviour”? Untuk lebih jelasnya saya ambil contoh dari bukunya Ian & Funge: Artificial Intelligence for Games 2nd Edition, di sana diberikan contoh sebuah robot yang bekerja seperti cleaning service,
yang pekerjaannya mencari, mengambil, dan memasukkan sampah ke tong sampah. Dari perilaku2x tsb jelas bisa direpresentasikan menjadi FSM biasa, akan tetapi ternyata robot ini juga bisa kehabisan battre. Jadi mau ga mau ketika batere udah mau habis, dia harus berpindah ke state charging.

Nah di situlah masalah utamanya, ‘alarm’ kondisi batere lemah bisa muncul kapan saja dan di mana saja yang berarti semua state harus juga mempunyai transisi ke state charging.

image

Dari gambar tsb, bisa dilihat jika semua state akan melakukan transisi ke state GetPower ketika robot kehabisan power. Jika kita hanya mengimplementasikan FSM seperti yang telah saya bahas sebelumnya, jelas akan sangat tidak efisien, karena kita perlu mendefinisikan transisi ke semua state.
Lalu apa solusinya? kalau di bukunya Ian & Funge sih langsung diimplementasikan aja yang namanya Hierarchical State Machine (HSM), namun berhubung ilmu saya yang belon nyampe maka dipakai lah teknik lain: “Membuat Global State”
Teknik ini sebenarnya sudah dijelaskan di bukunya Buckland: Programming Game AI by Example, yang intinya adalah kita membuat sebuah global state yang bertugas untuk melakukan checking kemungkinan terjadinya transisi tadi. Dan jika ada transisi, maka tinggal memaksa sebuah state untuk melakukan exit() dan berpindah ke state baru tersebut.

2. Implementasi
Untuk implementasinya sangat mudah, cukup melakukan sedikit perubahan di class FiniteStateMachine nya saja, dan membuat state baru yaitu global state.
Class FiniteStateMachine:
   1: package com.pzuh.statemachine
   2: {    
   3:     public class FiniteStateMachine
   4:     {
   5:         private var currentState:IState;
   6:         private var globalState:IState;
   7:         
   8:         public function FiniteStateMachine() 
   9:         {
  10:             currentState = null;
  11:             globalState = null; 
  12:         }    
  13:         
  14:         public function update():void
  15:         {
  16:             currentState.update();
  17:             globalState.update();
  18:         }
  19:         
  20:         public function changeState(state:IState):void
  21:         {
  22:             currentState.exit();
  23:             currentState = state;
  24:             currentState.enter();
  25:         }
  26:  
  27:         //getter setter
  28:         public function setGlobalState(state:IState):void
  29:         {
  30:             globalState = state;
  31:         }
  32:         
  33:         public function setCurrentState(state:IState):void
  34:         {
  35:             currentState = state;
  36:         }
  37:         
  38:         public function getCurrentState():IState
  39:         {
  40:             return currentState;
  41:         }
  42:     }
  43: }

6: Selain mendeklarasikan currentState, kita deklarasikan juga sebuah globalState

14: Pada method update(), kita juga memanggil method update yang dimiliki oleh globalState


Class GlobalState:

   1: package states 
   2: {
   3:     import com.carlcalderon.arthropod.Debug;
   4:     
   5:     import entities.*;
   6:     
   7:     public class GlobalState implements IState
   8:     {
   9:         private var myEntity:Miner;
  10:         
  11:         public function GlobalState(entity:Miner) 
  12:         {
  13:             myEntity = entity;
  14:         }
  15:         
  16:         /* INTERFACE IState */
  17:         
  18:         public function enter():void 
  19:         {
  20:             
  21:         }
  22:         
  23:         public function update():void 
  24:         {
  25:             if (batteryIsLow())
  26:             {
  27:                 myEntity.getStateMachine().changeState(new ChargingState(myEntity));
  28:             }
  29:         }
  30:         
  31:         public function exit():void 
  32:         {
  33:             
  34:         }        
  35:     }
  36: }


23: Pada method update() inilah sebuah kondisi global akan dicek, dan ketika kondisi tersebut terpenuhi maka global state ini akan mengubah current state ke state baru


Class Agent:

   1: public function Robot(name:String) 
   2:         {
   3:             super(name);
   4:             
   5:             stateMachine = new StateMachine();            
   6:         
   7:             stateMachine.changeState(new NyapuState(this));
   8:             stateMachine.setGlobalState(new GlobalState(this));
   9:         }

8: Dan jangan lupa kita masukkan GlobalState ini ke dalam state machine milik agent


3. Sekian

Yap, thats all. Cukup simple dan efisien terutama kalo statenya masih belum terlalu kompleks. Namun jika dirasakan sudah mulai kompleks, dianjurkan untuk mengimplementasikan Hierarchical State Machine (HSM).

4. Demo & Source Code?

Berhubung permasalahannya ga terlalu rumit + perubahan dan penambahan di source code juga tidak terlalu signifikan, maka demonya monggo di coba buat sendiri . Dan source codenya juga sengaja ga diupload karena saya juga males….

5. Referensi

Programming Game AI by Example, Matt Buckland
Artificial Intelligence for Games: 2nd Edition, Ian Millington

Freelance 2D game artist, occassional game developers, lazy blogger, and professional procrasctinator

0 comments: