Tarantool CE/EE Documentation portal logo
Помощь
Обновлена 15 сентября 2026 г. в 08:55

ГИС

Теперь рассмотрим catch() — основной метод игровой логики.

На вход поступают координаты игрока и идентификатор целевого покемона. Необходимо определить, поймал ли игрок покемона (напомним, что у каждого покемона есть шанс сбежать).

Сначала полученные данные игрока проверяются на соответствие Avro-схеме. Также проверяется, существует ли такой покемон в базе данных и отображается ли он на карте (покемон должен иметь статус active):

catch = function(self, pokemon_id, player)    -- check player data    local ok, tuple = self.player_model.flatten(player)    if not ok then        return false    end    -- get pokemon data    local p_tuple = box.space.pokemons:get(pokemon_id)    if p_tuple == nil then        return false    end    local ok, pokemon = self.pokemon_model.unflatten(p_tuple)    if not ok then        return false    end    if pokemon.status ~= self.state.ACTIVE then        return false    end    -- more catch logic to follow    <...>end

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

Для работы с географическими координатами используется модуль Tarantool gis.

Для простоты конкретная карта не загружается — предполагается, что используется карта мира. Входные координаты также не проверяются: считается, что все полученные местоположения находятся в пределах Земли.

Используются две гео-специфичные переменные:

  • wgs84 — последняя редакция стандарта World Geodetic System, WGS84. По сути, это стандартная система координат для Земли, представляющая её в виде эллипсоида.

  • nationalmap –- US National Atlas Equal Area. Это спроецированная система координат на основе WGS84. Она предоставляет нулевую базу для проекции местоположения и позволяет позиционировать игроков и покемонов в метрах.

Обе системы зарегистрированы в реестре EPSG Geodhetic Parameter Registry, где каждой системе присвоен уникальный номер. В коде эти номера назначаются соответствующим переменным:

wgs84 = 4326,nationalmap = 2163,

Для игровой логики нужна ещё одна переменная — catch_distance, которая определяет, на какое расстояние должен подойти игрок к покемону, чтобы попытаться его поймать. Зададим значение 100 метров.

catch_distance = 100,

Теперь можно вычислить результат. Текущие местоположения игрока (p_pos) и покемона (m_pos) проецируются на карту, проверяется, достаточно ли близко находится игрок к покемону (с помощью catch_distance), и вычисляется, пойман ли покемон (генерируется случайное значение, и покемон сбегает, если это значение оказывается меньше 100 минус шанс покемона):

-- project locationslocal m_pos = gis.Point(    {pokemon.location.x, pokemon.location.y}, self.wgs84):transform(self.nationalmap)local p_pos = gis.Point(    {player.location.x, player.location.y}, self.wgs84):transform(self.nationalmap)-- check catch distance conditionif p_pos:distance(m_pos) > self.catch_distance then    return falseend-- try to catch pokemonlocal caught = math.random(100) >= 100 - pokemon.chanceif caught then    -- update and notify on success    box.space.pokemons:update(        pokemon_id, {{'=', self.STATUS, self.state.CAUGHT}}    )    self:notify(player, pokemon)endreturn caught