MikRad → Утилитный класс для чтения настроек

В процессе разработки игр не раз убеждался что крайне полезно хранить все более-менее значимые настройки в одном месте, а именно — файле настроек. Этот подход имеет как минимум следующие преимущества —

  • все параметры и настройки локализованы в одном месте, а не хаотично разбросаны по классам проекта
  • возможность вносить изменения в настройки и смотреть изменения без перекомпиляции проекта

Хочу поделиться с сообществом небольшим утилитным классом для быстрого и удобного чтения настроек из xml-файла. Он позволяет имея файл настроек следующего вида —

<?xml version="1.0" encoding="UTF-8"?>
<settings>
	<app_settings>
		<property id="SCREEN_WIDTH" value="640" />
		<property id="SCREEN_HEIGHT" value="480" />
		<property id="FPS" value="50" />
		<property id="STAGE_SCALE_MODE" value="noScale" />
		<property id="PLAY_BUTTON_X" value="100" />
                ...................................................
	</app_settings>
</settings>


Легко читать его следующим образом —
var s:Settings = Settings.getInstance();
			
stage.frameRate = s.FPS;
stage.scaleMode = s.STAGE_SCALE_MODE;
.......................................


Структура файла настроек может быть другой, для этого надо изменить выборку аттрибутов в методе getProperty. Т.е. класс по сути делает мэппинг своих фэйковых пропертей на одноименные аттрибуты файла настроек. Класс также можно легко модифицировать в релизной версии для чтения заэмбеженного xml-файла.

Собственно, сам класс —

package  
{
	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.utils.flash_proxy;
	import flash.utils.Proxy;

	public dynamic class Settings extends Proxy implements IEventDispatcher
	{
		
		public function Settings() 
		{
			if (m_instance)
				throw new Error("Use Settings.getInstance()");
			
			m_event_dispatcher = new EventDispatcher();
			var urlRequest:URLRequest = new URLRequest(m_url);
			m_url_loader = new URLLoader();
			m_url_loader.addEventListener("complete", onDataLoaded)
			m_url_loader.addEventListener("ioerror", onDataFailed)
			m_url_loader.load(urlRequest);
		}
		
		public static function getInstance():Settings 
		{
			if (m_instance == null) 
			{
				m_instance = new Settings();
			}
			
			return m_instance;
		}		
		
		private function onDataLoaded(e:Event):void 
		{
			m_data = XML(m_url_loader.data);
			
			dispatchEvent(new Event("SETTINGS_LOADED"));
		}		
		
		private function onDataFailed(e:ErrorEvent):void 
		{
			trace(e);
		}
		
		override flash_proxy function getProperty(name:*):*
		{
			var str:String = name; 

			return m_data.app_settings.property.(@id == str).@value;
		}		
		
		public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void 
		{
			m_event_dispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);
		}
		
		public function dispatchEvent(event:Event):Boolean 
		{
			return m_event_dispatcher.dispatchEvent(event);
		}
		
		public function hasEventListener(type:String):Boolean 
		{
			return m_event_dispatcher.hasEventListener(type);
		}	
		
		public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void 
		{
			m_event_dispatcher.removeEventListener(type, listener, useCapture);
		}		
		
		public function willTrigger(type:String):Boolean 
		{
			return m_event_dispatcher.willTrigger(type);
		}
		
		private static var m_instance:Settings;
		
		private var m_url:String = "settings.xml";	
		private var m_url_loader:URLLoader;
		private var m_data:XML;
		private var m_event_dispatcher:EventDispatcher;
	}
}


Буду рад если кому-то этот класс окажется полезным. Спасибо за внимание.
  • +8
  • 19 октября 2011, 14:15
  • MikRad

Комментарии (14)

RSS свернуть / развернуть
+
+3
Вот смотрю на современные тенденции в программировании и удивляюсь. Это не правильно. Так не должно быть.

Обычный ini формат в 100 раз лучше поддерживается вручную + элементарно парсится двумя сплитами:

SCREEN_HEIGHT=480
FPS=50
STAGE_SCALE_MODE=noScale
PLAY_BUTTON_X=100

Ну а в целом подход с вынесением настроек правильный, конечно. :)
avatar

GameTelegraph

  • 19 октября 2011, 14:42
+
+5
На самом деле всякие хранения настроек, данных итд во внешних файлах (а то и вынесение части логики в скрипты) это очень важно для жестко компилируемых проектов. Когда смена простых, но захардкоженных данных выливается в долгую пересборку проекта. В нашем же случае можно хардкодить все что хошь, главное чтобы было оно в понятном одном месте. Ведь если нормально настроил все — перекомпиляция это меньше секунды для самого навороченного проекта даже на слабом компе. А так — что xml лежил рядом, что as файл — какая разница? Я сначала тоже xml делал, что для уровней, что для дорог, что для текста. Но потом просто увидел, что это лишние промежуточные файлы. Так что плаг к флешу у меня сразу генерил нужный AS файл в нужное место. Не нужно никакого кода разборки xml итд.
На самом деле даже данные для баланса можно в игре прямо на ходу в консоли подтюнивать, а потом нажать педаль и сгенерить AS файл.
avatar

scmorr

  • 19 октября 2011, 15:08
+
0
На счёт времени компиляции — это да. Но тут ещё, например, геймдизайнер, не имеющий у себя на компе инструментов для сборки, может «играться» параметрами и видеть сразу результат.
avatar

MikRad

  • 19 октября 2011, 17:07
+
0
Да, а я уж привык что в 99% в нашем сегменте геймдиз==программер==одиночка-инди :)
avatar

scmorr

  • 19 октября 2011, 20:08
+
0
В большинстве случаев — да, но процент, я думаю, всё-таки поменьше. :)
avatar

MikRad

  • 19 октября 2011, 22:39
+
+1
INI слишком «плоский», он подходит только для хранения простых настроек.
XML универсальнее — им можно описать и уровни, и гуи, да все что угодно можно описать) Нужно извращаться, чтобы реализовать вложенность тегов и атрибуты в INI. Хотя вот в анриловском движке извратились все-таки :)
avatar

x10der

  • 19 октября 2011, 16:51
+
0
> INI слишком «плоский»…
Ну есть вариант задания разделов типа
[game]
a=1
[UI]
a=1
и т.д.

просто вместо A=1 писать
<DATASET><GAME><CONFIG><PROPERTIES><PUBLIC><PROPERTY id="A"><VALUE>1</VALUE><TYPE>Number</TYPE></PROPERTY></PUBLIC></PROPERTIES></CONFIG></GAME></DATASET>
это бесчеловечно! :)
avatar

GameTelegraph

  • 19 октября 2011, 20:23
+
+3
Обычный ини формат хорош, когда у тебя в конфиге четыре строчки. То есть для флеш игр, видимо, вполне подходит.

Что касается тенденций — загляни в конфиг софтины CruiseControl.NET — у нас на ней вертятся несколько проектов и параметров настроек там получается стопятьсот к кучей уровней вложенности и прочей чепухой. Юзать здесь ини было бы самоубийством.

XML хорош не только сам по себе для более-менее сложных данных, а больше скорее дополнительными плюшками — вроде трансформаций XSL и прочих.
avatar

NightmareZ

  • 19 октября 2011, 22:07
+
0
Ну мы же говорим в контексте флэш игр, да? :)
Понятно, что ini формат не универсальное средство от всех болезней, просто то, что легче поддерживать и легче обрабатывать априори лучше.

А так можно вообще настройки в бинарник упаковать, на RAID 50 записать и использовать дополнительный софт для их изменения с встроенным контролем версий, желательно еще через веб. :) А вы XML, XML…
avatar

GameTelegraph

  • 19 октября 2011, 22:58
+
+5
Мне JSON показался наиболее удобным для хранения конфига, очень удобночитаем.
avatar

vinch

  • 19 октября 2011, 17:28
+
0
Поддерживаю. У JSON-a очень много плюсов. Еще пробовал среди прочего вариант с csv. Но json как по мне идеальнее всего для проекта в котором геймдизайнер не является программистом.
avatar

1g0rrr

  • 19 октября 2011, 18:38
+
0
В 11-ом плеере появилась нативная поддержка JSON, что также играет в его пользу, кинул в parse() строку — на выходе экземпляр Object, красота.
avatar

Claymore

  • 19 октября 2011, 19:10
+
0
мне этого очень не хватало, а левые классы использовать не хотелось, наконец-то =)
avatar

Ewanse

  • 19 октября 2011, 19:58
+
+1
Спасибо за информацию, — надо будет покопать в этом направлении.
avatar

MikRad

  • 19 октября 2011, 19:31

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.