Sergey_Walter Posted February 13, 2013 Share Posted February 13, 2013 Народ помогите плиз! Смотрите, к примеру я создаю полигоны: 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
Flaker Posted February 13, 2013 Share Posted February 13, 2013 Я так понял ты делаешь систему turf war'ов... Можно конечно с помощью костылей кой-каких выправить это дело... Но вобще, проще изменить логику... Зачем тебе вобще обнулять gangid... Ведь можно избежать этого, таким образом: 1) Игрок заходит в зону, ему присваивается id этой зоны (Учитываем, что все зоны есть в глобальном массиве) При выходе из этой зоны ничего не обнуляем! Вобще ничего не делаем! 2) При начале захвата, допустим по команде /turf, идет проверка на наличие игрока в захватываемой зоне... Если игрок присутсвует, то все ок, если нет, то все не ок... При таком алгоритме тебе не страшны траблы с колшейпами Link to comment
Sergey_Walter Posted February 13, 2013 Author Share Posted February 13, 2013 Вот в чём прикол, как определить находится ли он в этой зоне или нет? Нет же такой функции в мта на подобе самповской 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
Vamp1r Posted February 13, 2013 Share Posted February 13, 2013 Проще всего в данном случае использовать таблицы. При инициализации каждой зоны создаем для ее таблицу, в которой хранится вся информация о ней и в ней же хранится указатель на саму 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
Flaker Posted February 14, 2013 Share Posted February 14, 2013 Вот в чём прикол, как определить находится ли он в этой зоне или нет? Нет же такой функции в мта на подобе самповской PlayerToPoint https://wiki.multitheftauto.com/wiki/IsElementWithinColShape Vampir, нет, ну это п**дец какой-то) Конечно можно вручную проверять по координатам, но колшейпы могут быть не только квадратные! Они вобще многоугольниками могут быть или цилиндром, или даже сферой! Так что isElementWithinColShape для этого подойдет лучше! И вобще зачем каждый ключ массива в разнобой записывать, a не сразу при инициилизации? Разве так не удобнее?: local asocArray = { ["Key1"] = "val"; ["Key2"] = "val2"; } Link to comment
Sergey_Walter Posted February 14, 2013 Author Share Posted February 14, 2013 Всё, всем огромное спасибо, оба помогли! запилил так: 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
Vamp1r Posted February 14, 2013 Share Posted February 14, 2013 Flakker, да, совершенно забыл про функцию isElementWithinColShape Колшейпы цилиндры или сферы для турфов - это не то, само оптимально прямоугольник. Link to comment
Sergey_Walter Posted February 14, 2013 Author Share Posted February 14, 2013 isElementWithinColShape срабатывает не корректно при переходе с одной зоны в другую, что то её перебивает и она не успевает сработать =( Пришлось использовать пример Vamp1r. Link to comment
Flaker Posted February 14, 2013 Share Posted February 14, 2013 isElementWithinColShape отлично работает! Я не понимаю зачем вобще проверять что то при переходе! Почитай то что я написал во стором посте, на мой взгляд, это наиболее универсальный алгоритм... И он должен отлично работать, естественно при правильном использовании! Link to comment
Vamp1r Posted February 14, 2013 Share Posted February 14, 2013 isElementWithinColShape отлично работает! Я не понимаю зачем вобще проверять что то при переходе! Почитай то что я написал во стором посте, на мой взгляд, это наиболее универсальный алгоритм... И он должен отлично работать, естественно при правильном использовании! Проверка при заходе игрока в зону необходима, например, для учета количества нападающих. Ведь куда интереснее будет, когда от количества нападающих на зону она захватывается быстрее. А вот isElementWithinColShape пригодилась бы для самой первой аттаке, нежели для подключающихся игроков к атаке. Link to comment
Sergey_Walter Posted February 14, 2013 Author Share Posted February 14, 2013 Да, да Vamp1r ты прав.. У мну на самповском моде зоны на проверку по позиции было. Flaker, я вижу ты за оптимизацию, я тоже, но иногда бывают безысходные ситуации даже в самом лучшем на мой взгляд по функциям программирования мта Link to comment
Flaker Posted February 15, 2013 Share Posted February 15, 2013 Я просто стараюсь делать нормальные алгоритмы... Не стоит считать это безвыходной ситуацией? Рассказываю значит: Есть такая функция getElementsByType... С помощью нее и isElementWithinColShape, мы можем определить находится ли игрок в зоне... Это во-первых! Во вторых, если приблизится к тому варианту, который предпочитаете вы (То есть по заходу привязывать игрока к зоне)... Сделать это можно так: В эвенте OnColShapeHit заносить игрока в массив, привязанный к этой зоне... В эвенте onColShapeLeave убирать его из массива... В таком случае, вы сможете найти всех игроков, находящихся в зоне, пройдясь по массиву... Но такой вариант, имхо, менее удобен, так как имеет множество минусов, которые придется исправлять большим кол-вом кода... Link to comment
Vamp1r Posted February 15, 2013 Share Posted February 15, 2013 Рассказываю значит: Есть такая функция getElementsByType... С помощью нее и isElementWithinColShape, мы можем определить находится ли игрок в зоне... Это во-первых! Хм. Представим, что зон 300, а колшейп, примерно 10000. Если перебирать таблицу со всеми колшейпами, уйдет больше времени, нежели перебирать 300 известных. Во вторых, если приблизится к тому варианту, который предпочитаете вы (То есть по заходу привязывать игрока к зоне)... Сделать это можно так: В эвенте OnColShapeHit заносить игрока в массив, привязанный к этой зоне... В эвенте onColShapeLeave убирать его из массива... Опять же, всплывает массив. Если не пользоваться им изначально, его придется создать. Если пользоваться им изначально, то мы лишь добавим один элемент, например zoneInfo["attackersCount"]. И когда игроки будут входить или покидать зону мы будем прибавлять или отнимать значение от текущего. В таком случае, вы сможете найти всех игроков, находящихся в зоне, пройдясь по массиву... Но такой вариант, имхо, менее удобен, так как имеет множество минусов, которые придется исправлять большим кол-вом кода... Если пользоваться массивом изначально, то проходиться по ему уже не нужно, т.к. у игрока уже есть информация о текущей колшейпе, в которой он стоит. Нужно будет возвратить zoneInfo[инфа _из_игрока_о_его_колшейпе]["attackersCount"]. А если нужно будет найти всех игроков в колшейпе текущего игрока, то тут нам просто поможет getElementsWithinColShape . P.S. Мой вариант более оптимальный, т.к. практически вся информация о зоне будет храниться в таблице этой зоны. И для доступа к этой таблице, нам будет нужен только ее индекс, который хранится в игроке, породивший какое-то событие с зоной. Link to comment
Flaker Posted February 15, 2013 Share Posted February 15, 2013 Эммм... Я понял только %30 из написанного тобой... Ты не понял совсем, что я предлагаю сделать... Представим, что зон 300, а колшейп, примерно 10000. Какие, мать его, таблицы ты собираешь перебирать? isElementWithinColShape вернет тебе true, если игрок в зоне! Все! Этого достаточно! Если не пользоваться им изначально, его придется создать. Тоесть, в ином случае создавать не придется? P.S. Мой вариант более оптимальный, т.к. практически вся информация о зоне будет храниться в таблице этой зоны. И для доступа к этой таблице, нам будет нужен только ее индекс, который хранится в игроке, породивший какое-то событие с зоной. Не говори гоп... Да и не вижу я оптимальности в твоем варианте( Link to comment
Vamp1r Posted February 15, 2013 Share Posted February 15, 2013 Представим, что зон 300, а колшейп, примерно 10000. Какие, мать его, таблицы ты собираешь перебирать? isElementWithinColShape вернет тебе true, если игрок в зоне! Все! Этого достаточно! Ты говорил про getElementsByType. Если использовать getElementsByType("colshape"), то она вернет таблицу со всеми используемыми колшейпами. Отсюда и таблица и такое число (10000, например). Как я понял, ты не видишь смысла запоминать колшейпу, в которую вошел игрок. Но видишь смысл перебирать все колшейпы, когда они понадобятся. Отсюда я и высказался про не оптимальность твоего кода. Нет смысла спорить в оптимальности. Link to comment
Flaker Posted February 15, 2013 Share Posted February 15, 2013 Так вот я не собираюсь использовать getElementsByType("colshape") и перебирать кол-шейпы... Мой алгоритм в совершенно другом заключается! Согласен, не стоит спорить... Так как мы друг друга, просто напросто, не понимаем... Link to comment
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now