Achievements engine

А вот ещё класс от меня. Точнее даже не класс, а система классов плюс визуальный компонент… короче для краткости будем называть движком ачивок :)
И нужен, как вы уже наверно догадались, для менеджмента ачивок, хранения их значений между сессиями игры, отображение взятых ачивок и т.д.

Для всего этого безобразия нам потребуется куча классов которые я навыкладывал в предыдущих сериях, а именно Cookie.as, ageMath.as, ageVector.as, sounds.as, alphaFader.as. Все они уже есть в исходниках примера, так что отдельно качать ничего не надо.

Да я знаю что практика таскания кучи библиотек многим не по душе, однако я хочу отметить – я даю готовые решения, а не делаю уроки :) так что этот беспредел будет и дальше продолжаться. Я вообще подумываю собрать все наработки в какое-то подобие фреймворка, точнее даже темплейта, который можно будет загрузить и уже на основе него ваять новую игрушку :)

Ну ладна, от лирики к нашим баранам, то есть ачивкам.

Сразу смотрим как это работает:

Первые три кнопки – получение ачивки, последняя кнопка очищает все набранные достижения.

Все ачивки делятся на два типа – обычные и с параметром.
Обычные – это такие, которые получаешь за определённое действие, например пройти первый уровень.
С параметром – это когда например чтобы получить ачивку надо убить 5 монстров. Все текущие значения сохраняются внутри движка ачивок, так что ни о чём думать не надо.

Как же использовать движок ачивок в своих проектах? Во-первых надо добавить мовиклип achInfo на главную временную линейку. Его можно кастомизировать под стиль игры. Проще всего скопировать его из примера. Назовём этот экземпляр «achInfoClip».

Потом в классе ach в функции loadAllAch() записываем те ачивки, которые нам нужны. Можно конечно и напрямую вызывать addAchToDB(…) из главной программы. Это кому как удобно.

Далее инициализируем движок ачивок:

ach.init('myAch',achInfoClip);



где первый параметр – имя куки, в который будут сохранятся достижения, второй – имя нашего информационного мовиклипа.

Далее можно загрузить старые значения ачивок:

ach.loadAchFromCookie();



и можно уже получать достижения :) для простых ачивок есть функция:

ach.getAch('lev1');



для ачивок с параметром:

ach.incAchCnt('kill5');



Вот собственно и всё. Класс ach уже сам определит, была ли взята ачивка или нет. Если ещё нет – покажет информацию по ачивке через мовиклип achInfoClip. И конечно же сохранит результат в файл куки. Думаю довольно удобно.

Обнулить все результаты ачивок можно следующей функцией:

ach.initAchCookie();



Сам же код примера выглядит следующим образом. Из комментариев думаю всё ясно:

 
import main.*;
 
//инициализация движка ачивок
ach.init('myAch',achInfoClip);
 
//также нам потребуется звук
sounds.init(500,400);
 
//Загружаем старые ачивки
ach.loadAchFromCookie();
 
//Обновление информации по ачивкам
function updateTXT():void 
{
	txt.text="Achievements:\n\n";
	var iobj:String;
	for(iobj in ach.db)
	{
		txt.appendText(ach.db[iobj].title+' ');
		txt.appendText(ach.db[iobj].active?'on':'off');
 
		//Если ачивка количественная - выводим сколько осталось в процентах
		if(ach.db[iobj].cntNeed>0)
			txt.appendText('   completed '+ach.db[iobj].cntCur/ach.db[iobj].cntNeed*100+'%');
 
		txt.appendText('\n');
	}
 
 
}
updateTXT();
 
//кнопки получения ачивок
but1.addEventListener(MouseEvent.CLICK, but1_Click);
function but1_Click(e : MouseEvent):void 
{
	ach.getAch('lev1');
	updateTXT();
}	
 
but2.addEventListener(MouseEvent.CLICK, but2_Click);
function but2_Click(e : MouseEvent):void 
{
	ach.getAch('dropAb');
	updateTXT();
}	
 
but3.addEventListener(MouseEvent.CLICK, but3_Click);
function but3_Click(e : MouseEvent):void 
{
	ach.incAchCnt('kill5');
	updateTXT();
}	
 
//Стереть все записанные ачивки
but4.addEventListener(MouseEvent.CLICK, but4_Click);
function but4_Click(e : MouseEvent):void 
{
	ach.initAchCookie();
	updateTXT();
}



Класс ach – главный класс движка ачивок. Здесь происходит всё управление:

package main 
{ 
     public class ach 
	 {
		   static public var db:Object=new Object(); //Все ачивки здесь
		   static public var achInfoMC:achInfo; //Мовиклип с инфой по ачивке
		   static public var cookieName:String; //Имя куки файла куда пишем ачивки
 
 
		   //Внутрение переменные
		   static private var iobj:String;
		   static private var myCookie:Cookie;
 
		   //создаём ачивки. Можно конечно вызывать извне класса но думаю так удобней
		   static public function loadAllAch() 
		   { 	
				addAchToDB("lev1","Beginner","Complete the first level.");
				addAchToDB("dropAb","Mad drop","Use 'Drop' ability four times during the battle.");
				addAchToDB("kill5","Warrior","Kill 5 enemies.",5);
 
 
		   }
 
			// Инициализация движка ачивок
			// _cookieName - имя кукиса куда пишем взятые ачивки
			// _achInfoMC - имя мовиклипа, отвечающего за отображение инфы по взятой ачивке
		   static public function init(_cookieName:String,_achInfoMC:achInfo) 
		   { 
		   		achInfoMC=_achInfoMC;
				cookieName=_cookieName;
 
				myCookie=new Cookie(cookieName);
 
				loadAllAch();	
           }
 
			// Добавление ачивки базу
			// _achName - имя ачивки по которой будем её вызывать
			// _achTitle - отображаемое имя ачивки
			// _achDsc - описание ачивки
			// _achCnt - если не ноль - ачивка с параметром
		   static public function addAchToDB(_achName:String,_achTitle:String,_achDsc:String,_achCnt:int=0) 
		   { 
				db[_achName]=new achItem(_achName,_achTitle,_achDsc,_achCnt);
		   }
 
		   // Загрузка ачивок из кукисов
		   static public function loadAchFromCookie() 
		   {
				for(iobj in db)
				{
					db[iobj].active=Boolean(myCookie.get(iobj+'_active'));
					db[iobj].cntCur=int(myCookie.get(iobj+'_cntCur'));
				}
		   }
 
		   // Обнуление всех ачивок
		   static public function initAchCookie() 
		   {
				for(iobj in db)
				{
					myCookie.putNoFlush(iobj+'_active',0);
					myCookie.putNoFlush(iobj+'_cntCur',0);
					db[iobj].active=false;
					db[iobj].cntCur=0;
				}
				myCookie.flushData();
		   }
 
		   // Записать получение ачивки с именем ach_name
		   static public function getAch(ach_name:String) 
		   {
			    //Берём ачивку только если она уже не взята
			   	if(!db[ach_name].active)
				{
		   			db[ach_name].active=true;
					if(sounds) sounds.PlaySnd("snd_ach");
					achInfoMC.showAch(ach.db[ach_name]);
					myCookie.put(ach_name+'_active',db[ach_name].active);
					return true;
				}
				return false;
		   }
 
		   // Установить параметр ачивки ach_name в значение ach_cnt
		   static public function setAchCnt(ach_name:String,ach_cnt:int) 
		   {
			   	if(!db[ach_name].active)
				{
		   			db[ach_name].cntCur=ach_cnt;
					myCookie.put(ach_name+'_cntCur',db[ach_name].cntCur);
 
					//Если параметр ачивки достиг максимального значения - получаем ачивку
					if(db[ach_name].cntCur>=db[ach_name].cntNeed)
					{
						db[ach_name].active=true;
						db[ach_name].cntCur=db[ach_name].cntNeed;
						if(sounds) sounds.PlaySnd("snd_ach");
						achInfoMC.showAch(ach.db[ach_name]);
						myCookie.put(ach_name+'_active',db[ach_name].active);
						return true;
					}
				}
				return false;
		   }
 
		   // Увеличить на единицу параметр ачивки ach_name
		   static public function incAchCnt(ach_name:String) 
		   {
			   setAchCnt(ach_name,db[ach_name].cntCur+1);
		   }
	 }
}


Класс achItem – описывает одну ачивку. В этом классе хранится только информация:

package main 
{ 
     public class achItem 
	 {
		   public var name:String; //имя ачивки по которой будем её вызывать
		   public var title:String; //отображаемое имя ачивки
		   public var desc:String; //описание ачивки
 
		   public var active:Boolean; //взята ли ачивка
 
		   public var cntNeed:int; //если не ноль - ачивка с параметром
		   public var cntCur:int; //текущее значение параметра ачивки
 
	 	   //Конструктор класса ачивки - все пораметры соотвествуют названиям выше )
		   public function achItem(_name:String,_title:String,_desc:String,_cntNeed:int=0) 
		   {
			    name=_name;
 				title=_title;
				desc=_desc;
				cntNeed=_cntNeed;
 
				cntCur=0;
				active=false;
           } 
	 }
}


Класс achInfo – панелька с информацией, которая выскакивает каждый раз, когда мы берём ачивку. Её легко кастомизировать под свой проект. Хочу обратить внимание на мовиклип achPic. В нём хранятся все пиктограммы достижений. Все кадры в нем поименованы так же, как и ачивки в программе. Однако если такой пиктограммы нет, то будет выбрана пиктограмма по-умолчанию – первый кадр с именем ‘ok’.

package main 
{ 
	import flash.utils.*;
	import flash.events.*;
     public class achInfo extends alphaFader 
	 {
		   //Время показа инфы по взятой ачивке
		   private const TIME_TO_SHOW:int=4000;
 
		   //таймер для исчезновения этого мовиклипа
		   private var removeTimer:Timer;
 
		   public function achInfo() 
		   {
 				removeTimer= new Timer(TIME_TO_SHOW,1);
				removeTimer.stop();
				removeTimer.addEventListener(TimerEvent.TIMER, removeTimer_Timer);	
				visible=false;
 
           } 
 
		    //Показать эту панель с инфой по ачивке thisAch
			public function showAch(thisAch:achItem):void 
			{
				achObj.achPic.gotoAndStop(thisAch.name);
				achObj.titleTxt.text=thisAch.title;
				achObj.descTxt.text=thisAch.desc;
				removeTimer.start();
				startFadeIn();
			}
 
		    //Плавное исчезновение панели
			function removeTimer_Timer(event:TimerEvent):void 
			{
				startFadeOut();
			}
	 }
}


Весь код примера можно скачать здесь: http://www.anegmetex.com/devblog/files/achEngine.rar

3 комментария к “Achievements engine

Оставить комментарий

Ваш email не будет опубликован. Обязательные поля отмечены *

+ 25 = 29

Вы можете использовать это HTMLтеги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>