Написание клиента-бота для schemaverse

в 7:59, , рубрики: canvas, game development, javascript, node.js, визуализация, игры для программистов, метки: , ,

image На хабре уже было упоминание о 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 клиента.
Существующие визуализаторы отображают только общую карту. Моей же целью было отображение, также, флота.

Выглядит это примерно так:
image
Я сделал при приближении кружочки планет больше, потому что они закрывались кораблями.

В наибольшем масштабе карта очень долго обновляется. Если ее перемещать или увеличивать тоже приходится долго ждать. Я не обновляю карту при каждом чихе, а жду, пока пользователь введет новые желаемые координаты. Карта реагирует на колесо мыши и перемешение. Клиент передает степень увеличения, смещение и размер требуемого рисунка. Сервер, на основе этих данных, запрашивает с базы обьекты, рисует их на 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

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js