Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Регистрация Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > Dukobpa3

Оценить эту запись

State-machine (конечный автомат, машина состояний)

Запись от Dukobpa3 размещена 25.12.2013 в 15:40
Обновил(-а) Dukobpa3 01.07.2014 в 19:11

Вот чуток ссылок для затравочки.

Хабр: тут тоже про стейт-машину есть
Хабр: Простые стейт-машины на службе у разработчика
Вики: Конечный автомат

Простейшая стейт-машина укладывается в один свич-кейс. Более сложная реализация может требовать более серьезного подхода к реализации каждого стейта.

Ну поехали.
Стейт-машина это такая штука, которая нужна если у нас есть объект, поведение которого меняется в зависимости от состояния.
Например самый просто вариант: Лампочка с выключателем.
Код AS3:
package {
	public class Lamp {
 
		/** Текущий стейт тру - включено, фолс - выключено. */
		private var _state:Boolean;
 
		public function Lamp() {
			_state = false;
		}
 
		/**
		 * Ставим стейт
		 * @param value true - вкл, false - выкл
		 */
		public function setState(value:Boolean):void {
			_state = value;
		}
 
		/**
		 * Геттер стейта
		 * @return
		 */
		public function getState():Boolean {
			return _state;
		}
 
		/**
		 * Если включено светится если выключено не светится.
		 * @return
		 */
		public function getLight():int {
			return _state ? 100 : 0;
		}
	}
}
Т.е. что у нас тут происходит. В лампочке ничего нету, кроме яркости. И есть два состояния вкл-выкл.
Вся соль, показывающая суть стейтмашины у нас в методе: getLight(). Метод у нас один. Но в зависимости от состояния лампочки работает по разному.
Внутри он проверяет текущее состояние и выдает яркость лампочки. Понятно что булевым стейтом код можно упростить, но для демонстрации ок.

Теперь пример чуть посложнее. Например Осадный танк из старкрафта. У него есть тех же два состояния: осада, свернутый.
В осаде у него урон побольше, и не может двигаться. В свернутом виде урон маленький, но он мобильный.
Код AS3:
package {
	public class Tank {
		public static const STATE_SIEGE:String = "stateSiege";
		public static const STATE_TANK:String = "stateTank";
 
		private var _state:String;
 
		private var _damage:Number;
		private var _speed:Number;
 
		public function Tank() {
			setState(STATE_TANK);
		}
 
		public function setState(state:String):String {
 
			// Если пытаемся установить состояние которое уже установлено
			// - просто ничего не делаем.
			if (state == _state) return _state;
 
			switch (state) {
				case STATE_TANK:
						_damage = 60;
						_speed = 20;
					break;
 
				case STATE_SIEGE:
						_damage = 120;
						_speed = 0;
					break;
			}
 
			return _state;
		}
 
		public function getState():String {
			return _state;
		}
 
		public function getDamage():Number {
			return _damage;
		}
 
		public function getSpeed():Number {
			return _speed;
		}
	}
}
Вот такой вот простейший пример. При установке стейта мы установили все настройки объекта согласно текущему состоянию, и в дальнейшем все геттеры параметров объекта будут выдавать актуальные значения.

И еще одно важное замечание. В случае с танком не всё так гладко. Описанная машина состояний не предполагает каких-то переходов между стейтами, она статична. Хотя касательно того же танка есть время пока он сворачивается и пока разворачивается. В этот период времени происходит так называемый transition между стейтами. В этот период танк не может ни двигаться ни атаковать.
Код AS3:
package {
	import flash.events.TimerEvent;
	import flash.utils.Timer;
 
 
	public class Tank {
		public static const STATE_SIEGE:String = "stateSiege";
		public static const STATE_TANK:String = "stateTank";
		public static const STATE_TRANSITION:String = "stateNone";
 
		private var _currentState:String;
		private var _pendingState:String;
 
		private var _damage:Number;
		private var _speed:Number;
 
		public function Tank() {
			setState(STATE_TANK);
		}
 
		public function setState(state:String):void {
 
			// Если пытаемся установить состояние которое уже установлено
			// Либо сейчас происходит транзишн - просто ничего не делаем.
			if (state == _currentState || _currentState == STATE_TRANSITION) return;
 
			_currentState = STATE_TRANSITION; // текущий ставим как транзишн
			_pendingState = state; // ставим ожидаемый стейт.
 
			// Пока происходит транзишн танк ничего не может делать
			_damage = 0;
			_speed = 0;
 
			// Запускаем транзишн. Для примера обойдемся таймером,
			// в реальности механизм транзишина может быть сложнее.
			var timer:Timer = new Timer(1000);
			timer.addEventListener(TimerEvent.TIMER_COMPLETE, onTransitionComplete);
			timer.start();
		}
 
		public function getState():String {
			return _currentState;
		}
 
		public function getDamage():Number {
			return _damage;
		}
 
		public function getSpeed():Number {
			return _speed;
		}
 
		private function onTransitionComplete(event:TimerEvent):void {
			// По завершении транзишина ставим настройки стейта
			switch (_pendingState) {
				case STATE_TANK:
					_damage = 60;
					_speed = 20;
					break;
 
				case STATE_SIEGE:
					_damage = 120;
					_speed = 0;
					break;
			}
 
			// Отмечаемся в самих переменных стейтов.
			_currentState = _pendingState;
			_pendingState = "";
		}
	}
}
Вот теперь красота. Надеюсь кому-то поможет и было интересно

Искренне ваш Разрешите откланяться.
Всего комментариев 7

Комментарии

Старый 26.12.2013 19:23 Dukobpa3 вне форума
Dukobpa3
 
Аватар для Dukobpa3
Апдейтил текст.
Старый 26.12.2013 19:49 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Код AS3:
public static const STATE_TANK:String = "stateTank";
public static const STATE_TRANSITION:String = "stateTank";
А при таком раскладе он вечноникакой или вечнотанк?
Старый 26.12.2013 19:50 Dukobpa3 вне форума
Dukobpa3
 
Аватар для Dukobpa3
Это епик-фейл) спасибо)
Старый 26.12.2013 20:19 СлаваRa вне форума
СлаваRa
 
Аватар для СлаваRa
ты с какого времени перешел на Java стайл в написании get\set ?
Старый 26.12.2013 20:27 Dukobpa3 вне форума
Dukobpa3
 
Аватар для Dukobpa3
Цитата:
Java стайл в написании get\set ?
Долго ломался какие аксессоры писать, решил что раз тутор для самых маленьких - буду использовать минимум подходов.
Старый 26.12.2013 21:05 alatar вне форума
alatar
 
Аватар для alatar
Если танк отсюда, то стоило бы ссылку привести.
Старый 26.12.2013 21:11 Dukobpa3 вне форума
Dukobpa3
 
Аватар для Dukobpa3
Танк не оттуда. Танк оттуда будет в следующей статье. Там более сложная реализация стейтов и уже задействован паттерн стейт. Здесь же простенькое на 20 строк и один класс.
 

 


Часовой пояс GMT +4, время: 13:06.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.