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

Hill Climb Racing для ВКонтакте

Почти полтора месяца разработки, и получился клон Hill Climb Racing :-)
Только называется он "Без Тормозов" и в нем планируется много фишек, которых нет в оригинале. Дальше, будет запуск в Одноклассниках.

Игра стрельнула очень хорошо, сервер уже не выдерживает пиковых нагрузок, в планах переходить на более мощный.

Играть тут http://vk.com/app4248811

P.S. как раз для этой игры и пришлось портировать на as3 WheelJoint из последней версии box2d

среда, 19 декабря 2012 г.

Обновление блога

Я совсем и забыл, про виджет ВК комментарии. Сегодня прикрутил его к блогу. Теперь не нужно регистрироваться на blogspot.com, чтобы оставить комментарий.

воскресенье, 9 декабря 2012 г.

Изменение качества флешки из Java Script

Статья относится к IFrame приложениям, в данном случае к встроенному на страницу флеш приложению.

В последнее время, у Creara Media, появились "тяжелые" баннеры. При их отображении мои игры начинают тормозить. Для решения данной проблемы, нужно выставить качество банера на минимум.

Существует 2 решения:
  1. Скачать креаровский js файл http://img.creara-media.ru/js/v3/cmblockvk.js и изменить вручную параметр quality для встраиваемых баннеров. Недостатком данного решения, является слежение за изменениями данного файла со стороны креары и правка обновлений с моей стороны.
  2.  С помощью javascript, изменить параметры у обьекта, через который встроена флешка.
Дальше приводится функция на javascript, которая изменяет в runtime, качество флеш ролика.
function setLowQuality()
{
 var quality = "low";

 var objects = document.getElementsByTagName('object');

 for (var i = objects.length - 1; i >= 0; i--)
 {
  var obj = objects[i];
  var paramsTags = obj.getElementsByTagName('param');

  for (var j = paramsTags.length - 1; j >= 0; j--)
  {
   var param = paramsTags[j];
   var paramName = param.getAttribute('name');

   if (paramName == 'quality')
   {
    param.setAttribute('value', quality);

    break;
   }
  }

  var parentNode = obj.parentNode;
  var objNode = parentNode.removeChild(obj);
  parentNode.appendChild(objNode.cloneNode(true));
 }
}
Данная функция, перебирает все теги с именем object(через них встраиваются баннеры креары), и в них ищется тег с именем quality, потом значение в нем изменяется на low. Данную функцию можно легко адаптировать под изменение только определенных баннеров.

Вызывать функцию нужно после того, как сработало событие window.onload, или внутри него.

Данная функция тестировалась на браузерах Chrome и Firefox. Если Вы найдете какой-нибудь баг, в этой функции, сообщите мне, т.к. я не являются js программистом :)

среда, 5 декабря 2012 г.

Переезд на новый сервер

Взял в аренду VPS, здесь. Несколько дней потратил на настройку сервера. Перечитал кучу статьей по настройке, раз 20 переустанавливал ОС(стоит Ubuntu). Короче, голова уже трещит от всего этого. Но зато, немного разобрался с работой в UNIX системах. Связка получилась такая: Nginx, php5, mysql, memcached, xcache.
Потихоньку приложения туда переезжают.

Переезд обусловлен не то, что сильными нагрузками на shared хостинг, а банальным желанием получить больше денег :). В ВК ограничен размер флэш приложения, и в некоторых играх, нет возможности добавить панель с рекламой, вот я и решил использовать iframe для таких случаев.

Для более простого интегрирования флэш приложения с iframe использовал библиотеку IFlash. Там все хорошо расписано, как с ней работать. К тому же рекомендую установить IFlash Helper.

А еще, теперь есть возможность определить, что у пользователя установлен AdBlock, и "обругать его" :). А делается это так(Java script):
//так как использую рекламу от креары, то и проверять будем креаровский блок
if (typeof(CMBlockVK) != typeof(Function))
{
  // установлен AdBlock
}
else
{
  // все ок, показываем рекламу
}
Короче, теперь можно творить все, что угодно, главное чаще делать бекапы :)

понедельник, 19 ноября 2012 г.

Кэширование запросов на сервере(велосипед)

При написании очередной игры для ВК, пришлось написать достаточно много(по моим меркам) серверного кода на php.
В игре имеется много игровых карт, для которых нужно построить топ игроков. Построение данного списка занимает, достаточно много(на самом деле это миллисекунды, но когда это делают много пользователей одновременно, то это может привести к достаточно серьезным задержкам) времени.

Для решения этой проблемы, приходится кэшировать результаты. Мой сервер находится на виртуальном хостинге, поэтому нет возможности использовать Memcached. Пришлось писать свой велосипед.

В MySql, заложен механизм кэширования запросов. Но при малейшем изменении данных, с которыми работает запрос, данные не будут браться из кэша, а генерироваться заново. В моем случае это не подходит. И мне нужно обновлять данные с определенной периодичностью, например каждые 2 минуты.

Первое, что пришло в голову - это создать memory таблицу и хранить данные в ней. Это позволит получить очень хорошую скорость работы, т.к. кэшированные данные будут хранится в оперативной памяти. Но на практике все оказалось немного по другому. В таблице с типом memory, есть ограничение на количество хранимого в ней текста, в размере 65536 байт. Данные, которые нужны были для построения топов игроков для всех карт, никак не помещались в данный диапазон, поэтому пришлось создать обычную таблицу.

Sql запрос создания таблицы для хранения кэшированных данных:
CREATE TABLE `CacheTable` (
  `name` varchar(32) NOT NULL,
  `data` blob,
  `expire` int(11) unsigned DEFAULT '0',
  `locked` int(1) unsigned DEFAULT '0',
  PRIMARY KEY (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251$$

Как видите, ничего сверхъестественного.
  • name - ключ, для хранения порции кэшированных данных.
  • data - текстовые данные неограниченного размера.
  • expire - время окончания хранения кэша.
  • locked - флаг для блокировки изменения кэша, когда кто-то уже записывает обновленные данные по этому ключу.
Теперь, нужно написать 3 функции для работы с кэшем.
  1. Запись в кэш.
  2. Чтение из кэша.
  3. Блокировка кэша, по ключу.
Код функций выполняющих данные действия на php.
function CacheGet($key)
{
    $query =  "SELECT ";
    $query .= "  data ";
    $query .= "FROM ";
    $query .= "  CacheTable ";
    $query .= "WHERE ";
    $query .= "  name = \"".$key."\" ";
    $query .= "  AND (expire > ".time()." OR locked = 1)";

    $result = mysql_query($query);

    if ($result == false)
       return false;

    $data = mysql_fetch_array($result, MYSQL_ASSOC);

    if ($data == false)
       return false;

    return $data['data'];
}

function CacheLock($key)
{
    $query =  "INSERT INTO CacheTable (name, locked) ";
    $query .= "  VALUES(\"".$key."\", 1) ";
    $query .= "ON DUPLICATE KEY UPDATE ";
    $query .= "  name = VALUES(name),";
    $query .= "  locked = VALUES(locked)";

    mysql_query($query);
}

function CacheSet($key, $data, $expire)
{
    $query =  "INSERT INTO CacheTable (name, data, expire, locked) ";
    $query .= "  VALUES(\"".$key."\", \"".mysql_real_escape_string($data)."\", ".(time() + $expire).", 0) ";
    $query .= "ON DUPLICATE KEY UPDATE ";
    $query .= "  name = VALUES(name), ";
    $query .= "  data = VALUES(data), ";
    $query .= "  expire = VALUES(expire), ";
    $query .= "  locked = VALUES(locked)";

    mysql_query($query);
}

И небольшой пример использования. Будем рассматривать, получение топа игроков по всем картам.
$cachedScores = CacheGet("players_top");    // берем текстовые данные из кэша

if ($cachedScores == false)
{
    // если время хранения кэша истекло, или такого ключа еще нет
    
    CacheLock("players_top");   // блокируем данный ключ

    $playersTopData = GetPlayersTopForAllMaps();    // получаем данные по всем картам
    
    $cachedScores = json_encode($playersTopData);    // преобразуем массив в текст
    
    CacheSet("players_top", $cachedScores, 120);    // записываем новые данные и задаем время жизни 2 минуты
}

echo $cachedScores;

Правка: 
По причине аренды VPS, я все кэширования переложил на Memcache(кстати, как оказалось, Memcache и Memcached - это разные расширения, хотя задача у них одна!). И был крайне удивлен, производительность моего велосипеда и Memcache, практически на одном уровне. Даже скажу больше, приведенное выше решение оказалось на доли миллисекунд быстрее :)

воскресенье, 18 ноября 2012 г.

Создание приложений для ВКонтакте (Часть 2)

В первой статье я описывал, как начать работать с ВК api. В этой я хочу поговорить о создании топа игроков и топа друзей.
Начнем с того, что хранить очки мы будем в БД на сервере. Базу данных будем использовать MySql, а серверный код будем писать на php. В данной статье не приводится код соединения с БД, проверка подлинности пользователя и прочие тривиальные вещи.

Таблицу, где будут хранится очки, назовем ScoresTable. Структура таблицы очень простая:
user_id unsigned int PK
score unsigned int

Рассмотрим поля подробнее.
  1. user_id - хранит id игрока, в данном случае это ВК id. Задано как primary key.
  2. score - лучший результат игрока. Очень важно! Для этого поля необходимо создать индекс, т.к. при построении списка идет сортировка по этому полю, индексирование поможет делать это очень быстро.

Сохранение очков


Sql запрос для сохранения очков:
INSERT INTO
    ScoresTable (user_id, score)
VALUES
    (1, 999)
ON DUPLICATE KEY UPDATE
    score = GREATEST(score, VALUES(score))

Код функции на php, которая заносит очки в БД.
function SaveScore($user_id, $score)
{
    mysql_query("INSERT INTO ScoresTable (user_id, score) VALUES(".$user_id.",".$score.") ON DUPLICATE KEY UPDATE score = GREATEST(score, VALUES(score))");
}
Данный запрос вставляет новую строку в БД ScoresTable, и если запись для пользователя с таким id уже существует, то она просто обновляется.

Топ игроков


Для получения 100 лучших игроков, нужно создать запрос к БД, обработать полученные данные и отправить их клиенту(флэш приложение).

Создадим такой запрос:
SELECT
  *
FROM
  ScoresTable
ORDER BY score DESC
LIMIT 100

Теперь php код, которые выполняет данный запрос и обрабатывает результат:
function GetPlayersTop()
{
    $result = mysql_query("SELECT * FROM ScoresTable ORDER BY score DESC LIMIT 100");
   
    $users = array();
   
    while ($user = mysql_fetch_assoc($result))
    {
        $users[] = $user;
    }
   
    return $users;
}
Данная функция, вернет массив в котором каждый элемент будет массивом с полями user_id и score.

Топ друзей


Построение топа друзей, немного отличается от построения глобального топа. Для его построения, нам нужно иметь список друзей, у которых установлено данное приложение. Получить его можно 2-мя способами: на клиенте, на сервере. Лучше это делать на клиенте, таким образом мы снимаем нагрузку на сервер.

Для получения списка друзей, у которых установлено ваше приложение, существует метод friends.getAppUsers, он возвращает массив с id друзей.

Теперь при запросе к серверу для получения топа друзей, необходимо передать(на ваше усмотрение, get или post методом) строку, содержащую  id друзей разделенных запятыми.
Например:
3456, 3567, 87836, 88372

MySql запрос, который вернет топ друзей:
SELECT
  *
FROM 
  ScoresTable
WHERE user_id in (/* список id друзей, разделенных запятыми */)

И php код:
function GetFriendsTop($friendsList)
{
    $result = mysql_query("SELECT * FROM ScoresTable WHERE user_id in (".$friendsList.")");
    
    $users = array();
    
    while ($user = mysql_fetch_assoc($result))
    {
        $users[] = $user;
    }
    
    return $users;
}

 

Ответ сервера 


Возвращать результат будем в формате JSON.
Ниже приведен пример ответа:
$friendsList = mysql_real_escape_string($_POST['friends_list']);
    
$response = array();
$response['players_top'] = GetPlayersTop();
$response['friends_top'] = GetFriendsTop($friendsList);

echo json_encode($response);

среда, 5 сентября 2012 г.

Накопились игры

Продолжаю делать маленькие игры для ВКонтакте и вот насобиралось несколько штучек =)

Ragball
Игра про регдольчик. Нужно продержатся как-можно дольше уворачиваясь от лезвий.


Цепочки
Игра по типу Матч3, нужно собрать как-можно больше кристаллов за 1 раз.

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

Попробуй выжить
Переделанная для ВКонтакте игра Try2Survive.

Во всех играх используется реклама от CrearaMedia