Jump to content

Массив и полигоны


Recommended Posts

Народ помогите плиз! Смотрите, к примеру я создаю полигоны:

local colcircle = { } 

создаю их в цикле...

colcircle[row.id] = createColRectangle ( row.x, row.y, 100.0, 100.0 ) 

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

addEventHandler ( "onColShapeHit", colcircle[row.id], function(thePlayer) 
    setElementData(thePlayer, "gangid", row.id, true ) 
    outputChatBox("onColShapeHit") 
end) 

Так как полигоны стоят впритык к друг другу, ты например заходишь на другой полигон, то событие onColShapeLeave происходит наперёд чем onColShapeHit, а нужно чтоб обнулило и заменило на ид другого полигона. Делал событие onColShapeLeave выше события onColShapeHit, таже проблема, но иногда бывало норм

addEventHandler ( "onColShapeLeave", colcircle[row.id], function(thePlayer) 
    setElementData(thePlayer, "gangid", 0, true ) 
end) 

Делал второе событие за пределами функции создания полигонов, но там незадача с таблицей, как я туда впишу все айди полигонов без цикла, цикл то туда не впихнёшь, ну или наверно есть возможность как нить обозначить чтоб он срабатывал на все айди полигонов:

addEventHandler ( "onColShapeLeave", colcircle[?], function(thePlayer)

setElementData(thePlayer, "gangid", 0, true )

end)

Вот видео записал как срабатывают onColShapeLeave и onColShapeHit, полигоны стоят впритык и срабатывают странно..

Link to comment

Я так понял ты делаешь систему turf war'ов...

Можно конечно с помощью костылей кой-каких выправить это дело... Но вобще, проще изменить логику...

Зачем тебе вобще обнулять gangid... Ведь можно избежать этого, таким образом:

1) Игрок заходит в зону, ему присваивается id этой зоны (Учитываем, что все зоны есть в глобальном массиве)

При выходе из этой зоны ничего не обнуляем! Вобще ничего не делаем!

2) При начале захвата, допустим по команде /turf, идет проверка на наличие игрока в захватываемой зоне...

Если игрок присутсвует, то все ок, если нет, то все не ок...

При таком алгоритме тебе не страшны траблы с колшейпами

Link to comment

Вот в чём прикол, как определить находится ли он в этой зоне или нет? Нет же такой функции в мта на подобе самповской PlayerToPoint. Вот скрипт системы:

mysql = exports.mysql 
  
local toLoad = { } 
local threads = { } 
local null = mysql_null() 
local gangzone = { } 
local colcircle = { } 
local gangZonesElement = { } 
  
function loadAllGangZones(res) 
    local result = mysql:query("SELECT id FROM `gangzones` ORDER BY `id` ASC") 
    if result then 
        while true do 
            local row = mysql:fetch_assoc(result) 
            if not row then break end 
             
            toLoad[tonumber(row["id"])] = true 
        end 
        mysql:free_result(result) 
         
        for id in pairs( toLoad ) do 
             
            local co = coroutine.create(loadOneGangZone) 
            coroutine.resume(co, id, true) 
            table.insert(threads, co) 
        end 
        setTimer(resume, 1000, 4) 
    else 
        outputDebugString( "loadAllGangZones failed" ) 
    end 
end 
addEventHandler("onResourceStart", getResourceRootElement(), loadAllGangZones) 
  
function resume() 
    for key, value in ipairs(threads) do 
        coroutine.resume(value) 
    end 
end 
  
function loadOneGangZone(id, hasCoroutine) 
    if (hasCoroutine==nil) then 
        hasCoroutine = false 
    end 
     
    local row = mysql:query_fetch_assoc("SELECT * FROM gangzones WHERE id = " .. mysql:escape_string(id) .. " LIMIT 1" ) 
    if row then 
         
        if (hasCoroutine) then 
            coroutine.yield() 
        end 
         
        for k, v in pairs( row ) do 
            if v == null then 
                row[k] = nil 
            else 
                row[k] = tonumber(row[k]) or row[k] 
            end 
        end 
        colcircle[row.id] = createColRectangle ( row.x, row.y, 100.0, 100.0 ) 
        gangZonesElement[row.id] = createElement("status", row.id) 
        if row.faction == 1 then 
            gangzone[row.id] = createRadarArea ( row.x, row.y, 100, 100, 0, 255, 0, 175 ) 
            setElementData(gangZonesElement[row.id], "status", row.faction, true ) 
        elseif row.faction == 2 then     
            gangzone[row.id] = createRadarArea ( row.x, row.y, 100, 100, 255, 0, 0, 175 ) 
            setElementData(gangZonesElement[row.id], "status", row.faction, true ) 
        else 
            gangzone[row.id] = createRadarArea ( row.x, row.y, 100, 100, 0, 0, 255, 175 ) 
            setElementData(gangZonesElement[row.id], "status", row.faction, true ) 
        end 
        addEventHandler ( "onColShapeHit", colcircle[row.id], function(thePlayer) 
            setElementData(thePlayer, "gangid", row.id, true ) 
        end) 
        addEventHandler ( "onColShapeLeave", colcircle[row.id], function(thePlayer) 
            setElementData(thePlayer, "gangid", 0, true ) 
        end) 
    end 
end 
  
function capture( thePlayer ) 
    local gangid = getElementData(thePlayer, "gangid") 
    if isInAllowed(thePlayer) ~= 0 then  
        outputChatBox ("#ff0500x #ffffffВы не можете атаковать банды", thePlayer, 0,0,0, true)  
        return true 
    end  
    if gangid == 0 then  
        outputChatBox ("#ff0500x #ffffffВы не находитесь на територии банды", thePlayer,  0,0,0, true) 
        return true 
    end 
    if isPlayerInBandOnline(gangid) then  
        outputChatBox ("#ff0500x #ffffffЗону банды которую вы хотите атаковать нет в онлайне", thePlayer,  0,0,0, true) 
        return true 
    end  
    setRadarAreaFlashing ( gangzone[gangid], true ) 
end 
addCommandHandler ( "capture", capture ) 
  
function isInAllowed( thePlayer ) 
    local theTeam = getPlayerTeam( thePlayer ) 
    local factionType = getElementData( theTeam, "type" ) 
    return factionType 
end 
  
function isPlayerInBandOnline(gangid) 
    local players = exports.pool:getPoolElementsByType("player") 
    for k, arrayPlayer in ipairs(players) do 
       if getElementData( arrayPlayer, "faction" ) == getElementData( gangZonesElement[gangid], "status" ) then return false end 
    end 
    return true 
end 

Link to comment

Проще всего в данном случае использовать таблицы. При инициализации каждой зоны создаем для ее таблицу, в которой хранится вся информация о ней и в ней же хранится указатель на саму radar area + colshape. В то время как в colshape будет хранится указатель на нужный элемент таблицы, в котором вся информация о зоне.

Что мы имеем? Игрок вошел в колшейп, ему через getElementData из колшейпа присваивается указатель на табличный элемент. Игрок пишет команду, например, /attackZone и там мы проверяем игрока на расположенность в той зоне, указатель на которую он содержит. Если игрок в данной зоне, то начинаем захват, если нет - сообщение об ошибке.

Это почти тоже самое что написал Flaker. Пример:

  
local zoneInfo = {} 
... 
-- инициализация всех зон из файла/базы в цикле, например, где i - счетчик 
zoneInfo[i] = {} 
zoneInfo[i]["x"] = -- достаешь нужные координаты  
zoneInfo[i]["y"] = -- 
zoneInfo[i]["width"] = -- 
zoneInfo[i]["height"] = -- 
-- заполнение таблицы другими данными 
zoneInfo[i]["radarArea"] = createRadarArea(x, y, width, height) 
zoneInfo[i]["colShape"] = createColRectangle(x, y, x+width, y+height) 
setElementData(zoneInfo[i]["colShape"], "type", "turf") -- для того, чтобы определить среди других колшейп, что данная колшейпа именно для зон, например в onColShapeHit 
setElementData(zoneInfo[i]["colShape"], "ID", i) -- присвоим ей текущий номер из счетчика 
... 
  
  
  

Вот примерно так инициализировать зону. Когда игрок входит в колшейп, сделать что-то типа такого:

  
addEventHandler("onColShapeHit", getRootElement(), 
    function(player, matchingDimension) 
        if(matchingDimension) then 
            if(getElementData(source, "type") == "turf") then 
                local id = getElementData(source, "ID") 
                if(getPlayerTurf(player) == id) then 
                   -- игрок в колшейпе зоны, присвоем ему ее ид 
                   setElementData(player, "turfID", id)  
                end 
            end 
        end 
    end 
) 
  
function getPlayerTurf(player) 
    local x, y, _ = getElementPosition(player) 
    for i, _ in ipairs(zoneInfo) do 
        if(x >= zoneInfo[i]["x"] and y >= zoneInfo[i]["y"] and x <= (zoneInfo[i]["x"]+zoneInfo[i]["width"]) and y <= (zoneInfo[i]["y"]+zoneInfo[i]["height"])) then 
            return i 
        end 
    end 
    return -1 
end 
  

Потом, при захвате просто проверять, getPlayerTurf(player) с getElementData(player, "turfID"). Если совпадают - захват.

P.S. Заранее извиняюсь, мог намудрить что-то лишнее, т.к. спать хочу. Может кто исправит.

Link to comment
Вот в чём прикол, как определить находится ли он в этой зоне или нет? Нет же такой функции в мта на подобе самповской PlayerToPoint

https://wiki.multitheftauto.com/wiki/IsElementWithinColShape

Vampir, нет, ну это п**дец какой-то) Конечно можно вручную проверять по координатам, но колшейпы могут быть не только квадратные! Они вобще многоугольниками могут быть или цилиндром, или даже сферой! Так что isElementWithinColShape для этого подойдет лучше!

И вобще зачем каждый ключ массива в разнобой записывать, a не сразу при инициилизации?

Разве так не удобнее?:

local asocArray = { 
["Key1"] = "val"; 
["Key2"] = "val2"; 
} 

Link to comment

Всё, всем огромное спасибо, оба помогли!

запилил так:

function loadOneGangZone(id, hasCoroutine) 
    if (hasCoroutine==nil) then 
        hasCoroutine = false 
    end 
     
    local row = mysql:query_fetch_assoc("SELECT * FROM gangzones WHERE id = " .. mysql:escape_string(id) .. " LIMIT 1" ) 
    if row then 
         
        if (hasCoroutine) then 
            coroutine.yield() 
        end 
         
        for k, v in pairs( row ) do 
            if v == null then 
                row[k] = nil 
            else 
                row[k] = tonumber(row[k]) or row[k] 
            end 
        end 
        zoneInfo[row.id] = { ["x"] = row.x, ["y"] = row.y, ["width"] = 100.0, ["height"] = 100.0 } 
        zoneInfo[row.id]["colShape"] = createColRectangle(zoneInfo[row.id]["x"], zoneInfo[row.id]["y"], zoneInfo[row.id]["width"], zoneInfo[row.id]["height"]) 
        if row.faction == 1 then 
            zoneInfo[row.id]["radarArea"] = createRadarArea(zoneInfo[row.id]["x"], zoneInfo[row.id]["y"], zoneInfo[row.id]["width"], zoneInfo[row.id]["height"], 255, 0, 0, 175) 
        elseif row.faction == 2 then     
            zoneInfo[row.id]["radarArea"] = createRadarArea(zoneInfo[row.id]["x"], zoneInfo[row.id]["y"], zoneInfo[row.id]["width"], zoneInfo[row.id]["height"], 0, 255, 0, 175) 
        else 
            zoneInfo[row.id]["radarArea"] = createRadarArea(zoneInfo[row.id]["x"], zoneInfo[row.id]["y"], zoneInfo[row.id]["width"], zoneInfo[row.id]["height"], 0, 0, 255, 175) 
        end 
        setElementData(zoneInfo[row.id]["colShape"], "faction", row.faction) 
        setElementData(zoneInfo[row.id]["colShape"], "type", "turf") 
        setElementData(zoneInfo[row.id]["colShape"], "ID", row.id) 
        addEventHandler("onColShapeHit", getRootElement(), 
        function(player) 
            if(getElementData(source, "type") == "turf") then 
                local id = getElementData(source, "ID") 
                if(getPlayerTurf(player) == id) then 
                   setElementData(player, "turfID", id) 
                end 
            end 
        end) 
        --addEventHandler ( "onColShapeLeave", colcircle[row.id], function(thePlayer) 
            --setElementData(thePlayer, "gangid", 0, true ) 
        --end) 
    end 
end 
  
function capture( thePlayer ) 
    local gangid = getElementData(thePlayer, "turfID") 
    if isInAllowed(thePlayer) ~= 0 then  
        outputChatBox ("#ff0500x #ffffffВы не можете атаковать банды", thePlayer, 0,0,0, true)  
        return true 
    end  
    if(getPlayerTurf(thePlayer) ~= gangid) then 
        outputChatBox ("#ff0500x #ffffffВы не находитесь на територии банды", thePlayer,  0,0,0, true) 
        return true 
    end 
    if isPlayerInBandOnline(gangid) then  
        outputChatBox ("#ff0500x #ffffffЗону банды которую вы хотите атаковать нет в онлайне", thePlayer,  0,0,0, true) 
        return true 
    end 
    outputChatBox ("#ff0500x #ffffffВы начали захват гангзоны", thePlayer,  0,0,0, true) 
    setRadarAreaFlashing ( zoneInfo[gangid]["radarArea"], true ) 
end 
addCommandHandler ( "capture", capture ) 
  
function isInAllowed( thePlayer ) 
    local theTeam = getPlayerTeam( thePlayer ) 
    local factionType = getElementData( theTeam, "type" ) 
    return factionType 
end 
  
function isPlayerInBandOnline(gangid) 
    local players = exports.pool:getPoolElementsByType("player") 
    for k, arrayPlayer in ipairs(players) do 
       if getElementData( arrayPlayer, "faction" ) == getElementData( zoneInfo[gangid]["colShape"], "faction" ) then return false end 
    end 
    return true 
end 
  
function getPlayerTurf(player) 
    local x, y, _ = getElementPosition(player) 
    for i, _ in ipairs(zoneInfo) do 
        if(x >= zoneInfo[i]["x"] and y >= zoneInfo[i]["y"] and x <= (zoneInfo[i]["x"]+zoneInfo[i]["width"]) and y <= (zoneInfo[i]["y"]+zoneInfo[i]["height"])) then 
            return i 
        end 
    end 
    return -1 
end 

С меня пиво...

Link to comment

isElementWithinColShape отлично работает! Я не понимаю зачем вобще проверять что то при переходе! Почитай то что я написал во стором посте, на мой взгляд, это наиболее универсальный алгоритм... И он должен отлично работать, естественно при правильном использовании!

Link to comment
isElementWithinColShape отлично работает! Я не понимаю зачем вобще проверять что то при переходе! Почитай то что я написал во стором посте, на мой взгляд, это наиболее универсальный алгоритм... И он должен отлично работать, естественно при правильном использовании!

Проверка при заходе игрока в зону необходима, например, для учета количества нападающих. Ведь куда интереснее будет, когда от количества нападающих на зону она захватывается быстрее.

А вот isElementWithinColShape пригодилась бы для самой первой аттаке, нежели для подключающихся игроков к атаке.

Link to comment

Да, да Vamp1r ты прав.. У мну на самповском моде зоны на проверку по позиции было. Flaker, я вижу ты за оптимизацию, я тоже, но иногда бывают безысходные ситуации даже в самом лучшем на мой взгляд по функциям программирования мта :D

Link to comment

Я просто стараюсь делать нормальные алгоритмы...

Не стоит считать это безвыходной ситуацией?

Рассказываю значит:

Есть такая функция getElementsByType... С помощью нее и isElementWithinColShape, мы можем определить находится ли игрок в зоне...

Это во-первых!

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

В эвенте OnColShapeHit заносить игрока в массив, привязанный к этой зоне... В эвенте onColShapeLeave убирать его из массива...

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

Link to comment

Рассказываю значит:

Есть такая функция getElementsByType... С помощью нее и isElementWithinColShape, мы можем определить находится ли игрок в зоне...

Это во-первых!

Хм. Представим, что зон 300, а колшейп, примерно 10000. Если перебирать таблицу со всеми колшейпами, уйдет больше времени, нежели перебирать 300 известных.

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

В эвенте OnColShapeHit заносить игрока в массив, привязанный к этой зоне... В эвенте onColShapeLeave убирать его из массива...

Опять же, всплывает массив. Если не пользоваться им изначально, его придется создать. Если пользоваться им изначально, то мы лишь добавим один элемент, например zoneInfo["attackersCount"]. И когда игроки будут входить или покидать зону мы будем прибавлять или отнимать значение от текущего.

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

Если пользоваться массивом изначально, то проходиться по ему уже не нужно, т.к. у игрока уже есть информация о текущей колшейпе, в которой он стоит. Нужно будет возвратить zoneInfo[инфа _из_игрока_о_его_колшейпе]["attackersCount"]. А если нужно будет найти всех игроков в колшейпе текущего игрока, то тут нам просто поможет getElementsWithinColShape .

P.S. Мой вариант более оптимальный, т.к. практически вся информация о зоне будет храниться в таблице этой зоны. И для доступа к этой таблице, нам будет нужен только ее индекс, который хранится в игроке, породивший какое-то событие с зоной.

Link to comment

:?

Эммм... Я понял только %30 из написанного тобой...

Ты не понял совсем, что я предлагаю сделать...

Представим, что зон 300, а колшейп, примерно 10000.

Какие, мать его, таблицы ты собираешь перебирать? isElementWithinColShape вернет тебе true, если игрок в зоне! Все! Этого достаточно!

Если не пользоваться им изначально, его придется создать.

Тоесть, в ином случае создавать не придется? :|

P.S. Мой вариант более оптимальный, т.к. практически вся информация о зоне будет храниться в таблице этой зоны. И для доступа к этой таблице, нам будет нужен только ее индекс, который хранится в игроке, породивший какое-то событие с зоной.

Не говори гоп...

Да и не вижу я оптимальности в твоем варианте(

Link to comment
Представим, что зон 300, а колшейп, примерно 10000.

Какие, мать его, таблицы ты собираешь перебирать? isElementWithinColShape вернет тебе true, если игрок в зоне! Все! Этого достаточно!

Ты говорил про getElementsByType. Если использовать getElementsByType("colshape"), то она вернет таблицу со всеми используемыми колшейпами. Отсюда и таблица и такое число (10000, например).

Как я понял, ты не видишь смысла запоминать колшейпу, в которую вошел игрок. Но видишь смысл перебирать все колшейпы, когда они понадобятся. Отсюда я и высказался про не оптимальность твоего кода.

Нет смысла спорить в оптимальности.

Link to comment

Так вот я не собираюсь использовать getElementsByType("colshape") и перебирать кол-шейпы... Мой алгоритм в совершенно другом заключается!

Согласен, не стоит спорить... Так как мы друг друга, просто напросто, не понимаем...

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...