вторник, 22 мая 2012 г.

RAFPUG в Челябинске (19.05.2012)

Двинул речь вот тут про это.

Особое спасибо Михаилу Антипину (техническому директору mimimigames.ru ) за помощь по теме антикеша на кешах ресурсов.

P.S.: Спасибо тем, кто прослушал мою "тираду". Объясняльщик из меня еще тот ;)

пятница, 27 апреля 2012 г.

Подстановка параметров в шаблон строки (ActionScript, string template)

Преамбула:
Имеются множество шаблонов строк как для вывода сообщений об ошибках, так и просто каких то фраз в диалоговых окнах.
Шаблон строки представляет из себя следующее: "Мама мыла {0} и гладила {1}, а потом еще разок помыла {0}. Наша мама {2}!".

Проблема:
Заменить параметры в шаблоне строки реальными значениями.

Решение:
Способ №1
/**
 * Подстановка параметров в шаблон строки
 * @param  source - шаблон строки
 * @param  ...params - параметры, если первый параметр массив то параметры берутся от туда
 * @return
 */
public function replaceParams(source:String, ...params):String {
  if (!source || !params || !params.length)
    return source;
  
  if (params[0] is Array)
    params = params[0];
    
  var regexp:RegExp = null; 
  for (var i:int = 0; i < params.length; i++) {
    regexp = new RegExp("\\{" + i + "\\}", "g"); 
    source = source.replace(regexp, params[i]);
  }
  
  return source;
}

// Пример:
var source:String = "Мама мыла {0} и гладила {1}, а потом еще разок помыла {0}. Наша мама {2}!";
trace(replaceParams(source, "раму", "штаны", "молодец"));
// or
trace(replaceParams(source, ["раму", "штаны", "молодец"]));
// выведет: Мама мыла раму и гладила штаны, а потом еще разок помыла раму. Наша мама молодец!
Прим.: как оказалось такого рода функционал по подмене параметрами реализован в методе StringUtil.substitute(), о чем я узнал немного позже. Ну да ладно, свой велос ближе к телу :)

Способ №2 (более монструозный и менее производительный)
/**
 * Вставка массива параметров
 * @param str - шаблон строки
 * @param params - массив с параметрами
 * @return строка заполненная параметрами
 */
public static function insertParametersIntoString(str:String, params:Array):String {
  if (str == "" || str == null) 
    throw new Error("Insert parameter in 'null' string. Target string = " + str + ". Number of parameter = " + params.length + ". Parameters = " + params.toString());
  
  for (var i:int = 0; i < params.length; i++) {
    try {
      str = strInsertParameter(str, i, params[i].toString());
    } catch (err:Error) {
      throw new Error("Insert null parameter in string. Target string = " + str + ". Number of parameter = " + i + ". Parameter = " + params[i].toString() + "Error: " + err);
    }
  }
  
  return str;
}

/**
 * Вставка параметра в указанную позицию
 * @param str - шаблон строки
 * @param paramIndex - индекс параметра в шаблоне
 * @param paramValue - значение параметра
 * @return строка заполненная параметрами
 */
public static function strInsertParameter(str:String, paramIndex:int, paramValue:String):String {
  var resultStr:String;
  var searchStr:String;
  var i:int;
  searchStr = "{" + paramIndex + "}";
  i = str.lastIndexOf(searchStr);
  if (i == -1)
    return str;

  while (i != -1) {
    str = str.slice(0, i) + paramValue + str.slice(i + searchStr.length, str.length);
    i = str.indexOf(searchStr);
  }

  return str;
}

// Пример:
var source:String = "Мама мыла {0} и гладила {1}, а потом еще разок помыла {0}. Наша мама {2}!";
trace(insertParametersIntoString(source, "раму", "штаны", "молодец"));
// выведет: Мама мыла раму и гладила штаны, а потом еще разок помыла раму. Наша мама молодец!

воскресенье, 8 апреля 2012 г.

Имитация ячейки scratch-лотереи (ActionScript, GameDev)



Преамбула:
Понадобилось как то раз в игре сделать такую вещь:
  1. Дан массив ячеек со скрытым содержимым
  2. Пользователь юлозя мышкой по ячейке открывает содержимое
Проблема:
Сделать процесс открытия ячейки похожим на процесс стирания в scratch-лотерее.

Решение:
Проблема сводится к решению двух задач:
  1. Отобразить результат стирания
    • накладываем на скрытый контент маску
    • "рисуем" на маске "стиралкой", тем самым открывая контент
  2. Проверить факт стирания достаточной площади ячейки для её открытия
    • при отпускании кнопки мыши снимаем битмапу со спрайта где отображается результат работы маски
    • смотрим какой процент прозрачных пикселей остался и принимаем решение открыть ячейку или нет

ScratchSlot

Alternative content

Get Adobe Flash player



Исходник (FlashDevelop project, 201 кб)

вторник, 6 марта 2012 г.

Пакетная проверка xml-файлов на валидность (ant)

Преамбула:
  • Приложение подгружает языковой xml-файл (соответствующий переданной локале) со строковыми в стандарте xliff.
  • Архитектура приложения такова, что если загруженный файл не валидный то приложение "прекращает работу".
  • Языковых файлов около 15 штук.
  • Загрузкой файлов на сервер занимается ant-build-скрипт.

Проблема:
Не допустить загрузку не валидных xml-файлов.

Решение:
Воспользуемся консольной утилитой xmllim, которая есть в *nix системах, а так же в комплекте cygwin для windows.
Например, файл для русского языка находится по пути: ${projectDir}\bin\ru\client_ru.xlf
Вот таким таском проверим перед загрузкой нужные нам языковый файлы:

   Validating lang files...
      
         
         
         
         
         ...
   
   OK

P.S.: Можно еще более ужесточить проверку подсунув xmllint дополнительно DTD описывающего структуру xml-файлов.

среда, 21 декабря 2011 г.

LoaderContext, утечки памяти (ActionScript)

Как бороться c утечками памяти при загрузке внешних swf-модулей рассказано в блоге Максима Фирсова:
http://snzflash.com/blog/?p=54

Программное создание transparency grid, check-текстуры/заливки (ActionScript)

Преамбула:
Частенько, для проверки объектов с прозрачностью, нужно было подкладывать что то пёстрое под них для того, чтобы лучше их визуально оценить. Приходилось каждый раз делать каляки-маляки в graphics низлежащего Shape/Sprite-а.
Не соврать, подобные каляки называются "transparency grid" или check-текстурой/заливкой в случае 3D-контекста.

Проблема:
Не заморачиваясь, легко и задорно создавать "transparency grid" в поданном на вход экземпляр Graphics.

Решение:
Не мудрствуя лукаво, решил сделать "transparency grid" как в фотошопе + задать возможность кастомизации параметров этой текстуры (на всякий случай).

Конечный результат приведенного ниже кода:

transparency grid
/**
 * Рисует check-текстуру
 * @param   canvas - экземпляр класса Graphics
 * @param   width - ширина требуемой текстуры
 * @param   height - высота требуемой текстуры
 * @param   cellSize - размер ячейки
 * @param   cellColors - массив с цветами для нечетной и четной ячеек в формате RGBA
 * @param   lineColor - цвет линии между ячейками в формате RGBA
 */
public function drawCheckFill(canvas:Graphics, width:Number, height:Number, cellSize:Number, cellColors:Array = null, lineColor:uint = 0x080808FF):void
{
   var colors:Array = cellColors || [0x111111FF, 0x202020FF];
   colors = colors.slice(0, 2);
   
   var cols:int = int(width / cellSize);
   var rows:int = int(height / cellSize);
   var color:uint = 0;
   for (var i:int = 0; i < cols; i++) 
   {
      for (var j:int = 0; j < rows; j++) 
      {
         color = colors[(i + j) % 2];
         canvas.beginFill(color >> 8, (color & 0x000000FF) / 0xFF);
         canvas.drawRect(i * cellSize, j * cellSize, cellSize, cellSize);
      }
   }
   canvas.endFill();

   canvas.lineStyle(1, lineColor >> 8, (lineColor & 0x000000FF) / 0xFF, true, LineScaleMode.NORMAL, CapsStyle.NONE);
   for (i = 0; i < cols; i++) 
   {
      canvas.moveTo(i * cellSize, 0);
      canvas.lineTo(i * cellSize, rows * cellSize);
   }
   
   for (i = 0; i < rows; i++) 
   {
      canvas.moveTo(0, i * cellSize);
      canvas.lineTo(cols * cellSize, i * cellSize);
   }
}      

var shape:Shape = new Shape();
drawCheckFill(shape.graphics, 170, 170, 8, [0XFFFFFFFF, 0xCCCCCCFF], 0);
P.S.: Кстати для создания текстур для материалов 3D-движков тоже сгодится.

воскресенье, 18 декабря 2011 г.

Пара приемов для windows-консоли (Windows, console)

Прием #1

Преамбула:
Как то давно стояла задача со следующей последовательностью действий:
  1. В БД Oracle запускался по шедулеру таск который брал файл(ы) из определенной директории, парсил их и складывал данные в таблицы, после чего запускался bat-файл который выполнял пункты ниже.
  2. Перенос файлов в zip/rar-архив.
  3. Перенос архивов в бекапную папку.
Так вот, экспериментальным путем было установлено, что надо делать небольшую паузу между п.2 и п.3 (видимо архиватор к моменту запуска п.3 не успевал "отпустить" архив).

Проблема:
Сделать паузу скушать твикс между задачами в bat-файле.

Решение:
Т.к. для паузы в батнике я ничего стандартного не нашел (какойнить wait, delay, sleep), то применил вот такой финт ушами:
ping localhost -n <примерное время в секундах>

Прием #2

Преамбула:
Есть задача со следующей последовательностью действий:
  1. Обновить проект (на тему появления новых строковых и графических ресурсов).
  2. Пройтись обфускатором по уже откомпеленному клиенту. (task secureClient)
  3. Залить клиента и ресурсы на сервер. (task upload)
п.2 и п.3 прописаны в ant-товском build.xml наряду с дугой кучей тасков.
Дефолтный таск = upload.
Т.к. описанные выше действия выполняются редко (максимум один раз в 1-2 недели по N-раз в день), то отчего то не хотелось отдавать это ant-у и без того замусоренного.

Проблема:
Выполнить последовательность действий одним "телодвижением".

Решение:
C:\Project>svn up & ant secureClient & ant