На хабре уже было упоминание о SQL играх. Но я все был занят и только недавно решил разобратся что-же это такое. Совершенно случайно я выбрал schemaverse о которой тоже уже упоминалось на хабре.
Насколько я понял, все удовольствие от игры получаешь, когда пишешь для нее бота. Для этого я выбрал один из самых своих любимых языков — javascript. Также я решил визуализировать карту, чтобы видеть как мои кораблики летают и захватываюи вражеские планеты. Много кода и SQL запросов я приводить не буду чтобы не раздувать статью, вы всегда можете посмотреть их в репозитории.
Алгоритм поведения бота я выбрал очень простой — построить добытчиков, построить захватчиков, и когда захватчиков станет достаточно — лететь захватывать. Еще, по ходу, строятся инженеры, которые ремонтируют корабли и, если хватает денег, я провожу апгрейд флота.
С самого начала я решил по минимуму использовать сторонние библиотеки. Итак, сначала устанавливаем соединение с базой.
var config = require('./config.js');
// Postgres connection
var pg = require('pg'),
conn = "pg://"+config.username+":"+config.password+"@db.schemaverse.com:5432/schemaverse";
var UserModel = require('./models/user');
var CommandProcessor = require('./command_processor');
pg.connect(conn, function(err, client) {
if (!err){
var userModel = new UserModel.constructor(client);
CommandProcessor(userModel);
} else {
console.log(err);
}
});
После установки соединения инициализируется пользователь и чтобы можно было смотреть некоторую статистику в консоле и запускать визуализатор я добавил обработчик команд.
При инициализации пользователя собирается информация о его планетах. Посройка добытчиков/захватчиков/инженеров производит каждая планета сама для себя. А заправка/апгрейд для всех кораблей.
Это пошаговая стратегия, причем зависимость длительности хода я так и не смог проследить. Поэтому я проверяю, завершился ли ход, в зависимости от длительности предыдущего хода. В начале нового хода, проверяется состояние кораблей и вызываются обработчики, что подписались на событе «tic». Информация о захвате новой планеты получается из списка ивентов. Для того, чтобы захватить планету достаточно успешно добыть из нее топливо. Это единственный ресурс игры. Также при каждом ходе поправляется курс и скорость всех летящих кораблей.
При захвате новой планеты, она добавляется в список планет и подписывается на событие «tic».
var tick = function(){
repair_damaged();
create_miners();
create_attackers();
go_to_conqueror();
}
//constructor
user.on(tick);
Следить за всем этим по выводу консоли не очень интересно. Я добавил модуль CommandProcessor с помощью которого можно в любой момент проверить состояние игры. В любой момент можно расширить список поддерживаемых команд. Но более подробно я хочу расказать о визуализаторе и о проблемах, с которыми мне пришлось столкнутся.
После ввода команды «map» первым делом создаются веб и websocket серверы.
var app = require('http').createServer(handler),
io = require('socket.io').listen(app, { log: false });
Визуализатор также подписывается на событие «tic» и передает сообщение клиентам, что можно обновить карту.
По сути веб-сервер нужен только для передачи статики, тоесть websocket клиента.
Существующие визуализаторы отображают только общую карту. Моей же целью было отображение, также, флота.
Выглядит это примерно так:
Я сделал при приближении кружочки планет больше, потому что они закрывались кораблями.
В наибольшем масштабе карта очень долго обновляется. Если ее перемещать или увеличивать тоже приходится долго ждать. Я не обновляю карту при каждом чихе, а жду, пока пользователь введет новые желаемые координаты. Карта реагирует на колесо мыши и перемешение. Клиент передает степень увеличения, смещение и размер требуемого рисунка. Сервер, на основе этих данных, запрашивает с базы обьекты, рисует их на canvas и передает обратно клиенту.
get_map_base64(
data.x,
data.y,
data.w,
data.h,
data.zoom,
data.render_planets,
data.render_ships,
function(img){
socket.emit('draw', img);
}
);
В теории сервер может рисовать только корабли или только планеты, но я пока это не использую.
Можно было оптимизировать скорость обновления карты, если: хранить список планет локально и изменять отдельние планеты по событию «conquer», и если брать не все карты из базы, а разбить на квадраты и брать по одной с квадрата.
Но их очень много чтобы хранить локально, я решил сэкономить память, а если брать по одной с квадрата, то при большом масштабе можно не увидеть свою начальную планету. Поэтому я решил пока не оптимизировать процес. К тому же, при большом увеличении все обновляется довольно быстро.
Ссылка за репозиторий проекта — https://github.com/peinguin/schemaverse_bot
Автор: peinguin